Rust你不认识的所有权

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Rust你不认识的所有权

全年无休的IT老兵   2023-02-03 我要评论

在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所有权的一些学习心得。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们