Rust你不认识的所有权

在Rust中是没有内存垃圾回收机制(GC)的,那Rust是如何保障内存安全的呢?这就引出了“所有权”这个概念。 我们看下下面这段伪代码

在Rust中是没有内存垃圾回收机制(GC)的,那Rust是如何保障内存安全的呢?这就引出了“所有权”这个概念。

我们看下下面这段伪代码

let s = "helloString";
t = s;
print(s);

在之前我们学习的语言中,比如C语言,对于上述伪代码的执行结果应该是正常打印"helloString" 的内容,但是在Rust中,执行上述代码时,会出现如下提示

------ 增加所有权返回内容;

而产生这个结果的原因就是触发了Rust语言中所有权机制:

  • Rust中的每一个值都有一个对应的变量作为它的所有者
  • 在同一时间内,值有且仅有一个所有者
  • 当所有者离开自己的作用域时,它持有的值就会被释放掉

在看这三条机制之前,需要先说明一下Rust中变量作用域的概念

作用域:一个对象在程序中有效的范围。

比如如下Rust代码

{
    let s = "hello";
}

在花括号内部就是变量s的作用域,当源码超出这个范围后,变量s将不再可用,即

{
    let s = "hello";
}
println!("{}", s);

打印这一句代码编译时会报错。因为在Rust语言中,当变量离开作用域时Rust会自动调用变量的"drop"函数,以此保障内存的快速回收。上述源码中,在代码执行到“}”时,Rust调用了变量s的drop函数,所以s指向的内存失效,从而导致在执行打印语句时会出错,也就是这个逻辑保障了Rust语言中内存的安全性。

我们再说回文章开头的伪代码例子,为什么编译时会出现问题,这里我们就要详细介绍一下这些语句在Rust中的逻辑。

let s = "helloString";

这句语句是声明了一个变量并使用“helloString”进行了初始化

简化展示,隐藏内部详细逻辑

t = s;

这个语句是将变量s的内容同时赋值给变量t,如下图,如果每次赋值的时候都全量内存拷贝一份的话,那整体语言性能会下降很多(毕竟变量地址大小还是不可确定的),所以处理方式是新建一个变量t,然后将内容内存指向s的指向地址。

上述情况下就出现了一个情况,同一个值被两个变量所指向,这个不符合Rust所有权的规则,所以Rust根据所有权做了一个语言限制,即当s赋值给新的变量t时,变量t指向s指向的内容,而变量s本身将被Rust擦除,所以在执行完赋值语句后,等号右侧(也就是s)将无效,在Rust语言中将这个行为叫做变量的移动,从字面意思理解也就是将变量s所有的值移动到变量t中,移动完成后s的生命周期也随之结束。

Rust有了移动这个概念,那对于其他语言中的深度拷贝或再次赋值的情况下Rust中该如何做呢?为了解决这个问题,Rust提出了另外一个变量与数据的交互方式——克隆,意思就是将s的数据完整的克隆一份给t,s的内容不变:

以Rust字符串数据结构为例子,可参考如下:

let s1 = String::from("hello");
let s2 = s1.clone();  // 此处为克隆的默认方法
println!("s1={}, s2={}", s1, s2); 

从执行结果可以看出,克隆后s1变量内容不变,还可以继续使用。

上述就是Rust所有权的一些学习心得。

到此这篇关于Rust你不认识的所有权的文章就介绍到这了,更多相关Rust所有权内容请搜索好代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持好代码网!

标签: Rust 所有权