Rust中的核心概念之一-Ownership
什么是Ownership Ownership是Rust中的一个核心特点,可以理解成是Rust做到内存安全的重要手段。不同于带GC的语言或是C/C++这样显式管理内存的语言,ownership系统实现了在编译期管理内存(但又不需要程序员过分手动介入)从而避免了GC开销。 硬要说的话个人感觉像是C++中的RAII,但是由于带有编译器级别的检查,比C++更不容易出错。 Ownership的规则 Rust中所有的值(value)都有一个作为所有者(owner)的变量(variable) (一个值)同时只能有一个owner(参考Rust中赋值的Move语义和在内存管理中起到的作用) 当owner离开作用域(scope)时,其对应的值(value)就会被释放(dropped)(无论是堆上还是栈上的) 解释 Variable Scope 和其他语言类似,变量离开作用域后,就失效了。当一个变量离开作用域时,Rust会自动调用drop 函数,释放内存 Heap and Stack 和C/C++一样,Rust的内存管理也分为堆和栈,栈上内存由操作系统自动管理,堆上内存需要程序员手动管理(Rust中通过Ownership规则和编译器自动插入释放内存的语句,避免像C/C++那样的显式管理) Move Rust中的简单赋值=大多类似于其他语言中的浅拷贝,仅拷贝栈上内容。在Rust中,这种变量和数据交互(interact)的方式称为Move。当发生Move(我理解为“实际”所有权的转移)后,原变量在离开作用域后,编译器不会插入drop,从而避免内存的重复释放 这里还引出Rust的另一个设计思想:Rust永远不会“自动”(automatically)去“深拷贝”数据。因此,默认赋值行为的运行时代价都可以认为是比较低的 String结构示例 let s1 = String::from("hello") let s2 = s1 Clone 那么如果我们真的需要深拷贝一块数据需要怎么做呢,在Rust中需要显式调用clone。这实际上也是显式提醒程序员,这里有一段特殊的代码要执行,有可能消耗会比较大 fn main() { let s1 = String::from("hello"); let s2 = s1.clone(); println!("s1 = {}, s2 = {}", s1, s2); } Another wrinkle: Stack-Only Data 一些简单数据类型,像整型,我们不调用clone,也不是Move语义,原因在于,这些简单类型在编译期就能确定大小,并且完全存储于栈上,所以拷贝比较快。 Rust中有一种特殊的注解(annotation) Copytrait, 实现了这个trait类型的变量在赋值后依然可以使用。但如果实现了Droptrait,Copy就无法使用 什么样的类型可以实现Copytrait呢?可以参考官方文档,通常来说,没有需要分配资源的类型可以实现。以下是一些实现了Copy的类型 所有整型,如u32 Boolean类型,bool 浮点型, 如f64 字符类型,char 元组(Tuples),当然只能包含同样实现Copy的类型,如(i32, i32)实现了,但(i32, String)没有 Functions 函数中传参和返回值也一样有ownership的转移问题,传参即赋值,返回值会将ownship move到调用它的函数 ...