rust所有权理解(备忘)

    最近闲的没事,就准备学习一下rust。 rust是Mozilla开发的一门编程语言。
rust是为了多核系统而设计的一门编程语言,它因其特殊的机制有线程安全性,编译期查出内存错误的优点,可能语法有着那么点另类,但我想这不是问题。至于它和另外一门编程语言GO的优缺点,请自行了解,因为我也是小白,并不敢发表什么高见。
本文只是用自己的语言再次理解了一些rust的所有权机制,官方的文档应该比我更加详尽。有兴趣的可以去看看,
地址: https://www.rust-lang.org/zh-CN/

正如上文所说,rust有编译期查错的能力以及线程安全的能力,这就是rust的特有机制,所有权机制。

首先我们先看一下所有权机制的规则(摘自官方文档):
1.Rust 中的每一个值都有一个叫做它的所有者(owner)的变量。
     2.同时一次只能有一个所有者
     3.当所有者变量离开作用域,这个值将被丢弃。

         我们接下来会用代码的形式来进行讲解,不懂的可以去官方文档看看语法。

首先我们看一段代码
{
        let x = String::from("test");
        println!("in scope hello this is {}", x);
    }
    println!("out scope hello this is {}", x);

         当然,这段代码是无法执行的,因为根本无法通过编译,报错如下
error[E0425]: cannot find value `x` in this scope
  --> src/main.rs:13:40
   |
13 | println!("out scope hello this is {}", x);
   |                                        ^ not found in this scope
  因为x在为这个String的值的所有者,在所有者离开作用域后值直接被释放了,这一点和其它编程语言是很相似的。


接下来我们看这一段代码
let x = String::from("123");
     let y = x;
     println!("x = {}, y = {}", x, y);

你们可能此时也已经在猜测运行结果了,很遗憾,这段代码也是无法运行的

报错为:
error[E0382]: use of moved value: `x`
  --> src/main.rs:11:32
   |
10 |     let y = x;
   |         - value moved here
11 |     println!("x = {}, y = {}", x, y);
   |                                ^ value used here after move
   |
   = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait

 报错上显示x的值被移动了,你们可能在想,这是什么鬼。我们接下来就来扯一下数据的内存吧

实际上x是所有者,指向了堆上的一块内存,因为在rust中,非基本数据类型都是存储在堆上的,其它语言基本也是这样的。而let x = String::from("123");这个语言实际上是将x指向了那块内存。而let y = x则是将y指向了与x指向内存相同的那块内存。在其它语言中也是这样的,因为复制堆上的数据对运行效率影响很大。如果你们有其它语言的基础,那么这个过程其实就是浅拷贝,同时你们也应该了解这样会导致什么错误的出现,即任何该值的所有者均可对这块内存进行修改甚至删除,而rust解决了这个问题,rust使第一个变量,即x无效化了,这样就不会出现上述的问题了,这个就是数据的移动,是不是很形象。

那么我们再看另外一段代码:

let x = 1;
     let y = x;
     println!("x = {}, y = {}", x, y);
是不是觉得这段代码也不能执行,这就错了,这段代码可以正常执行,并且运行结果如你所想。因为在rust中,基本数据类型是存储这栈上的,而对栈的拷贝操作对运行效率的影响是微乎其微的,所以对栈上数据的引用都是默认是拷贝的。所以对于上一段代码其实也是可以对x进行深拷贝从而让它成功运行的。但是这样正如前面所说的,会影响运行效率。所以rust为了兼顾运行效率和安全,它使用了无效化这个方法。当然这个方法也会导致相应的问题,例如:
fn hello(str: String)
    {
        println!("{}", str);
    }
    fn test()
    {
        let x = String::from("123");
        hello(x);
        println!("x = {}", x);
    }


这个会编译失败,报错为
error[E0382]: use of moved value: `x`
  --> src/main.rs:15:24
   |
14 |     hello(x);
   |           - value moved here
15 |     println!("x = {}", x);
   |                        ^ value used here after move
   |
   = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait

因为x的值已经被转移到了hello函数的str参数中了,所以x无效化了,故而会导致这个错误。这个问题我们当然可以通过让hello函数返回x的值来解决,但是这个解决办法略显蛋疼,而且rust已经为我们解决了更好的方案了,具体的我们下篇文章再讲,如果我记得写的话(笑:-D),当然你们也可以去看rust的文档。习惯了以rust的所有权系统来编程,你在编写其它编程语言的时候也能写成更加安全的代码

猜你喜欢

转载自blog.csdn.net/tjq980303/article/details/70859949