Rust所有权
程序的内存可以在以下位置分配:
栈(Stack)
堆(Heap)
栈
栈遵循后进先出的顺序,栈存储在编译时已知大小的数据值,例如,固定大小为i32的变量是栈存储的候选对象,因为它的大小在编译时是已知的。固定大小后,所有标量类型都可以存储在栈中。
考虑一个字符串示例,该字符串在运行时分配了一个值,其大小不能在编译时确定,因此它不是栈存储的候选对象,而是堆存储的候选对象。
堆
堆存储在编译时大小未知的数据值,用于存储动态数据,简而言之,将堆内存分配给在程序的整个生命周期中可能发生变化的数据值。
在内存中,堆与栈相比组织较少的区域。
什么是所有权?
Rust中的每个值都有一个变量,称为owner值。,Rust中存储的每个数据都会有一个与之关联的所有者。例如,在语法中: age = 30,age是值30的所有者。
每个数据一次只能拥有一个所有者;
两个变量不能指向相同的存储位置,变量将始终指向不同的存储位置。
所有权转移
值的所有权可以通过以下方式转移:
将一个变量的值分配给另一个变量;
将值传递给函数;
从函数返回值。
将一个变量的值分配给另一个变量
Rust的主要卖点是其内存安全性,通过严格控制谁可以在什么时候使用变量来实现内存安全。
请考虑以下代码段:
fn main(){ let v = vec![1,2,3]; //向量v在堆中拥有对象 //在任何给定时间只有一个变量拥有堆内存 let v2 = v; //这里有两个变量拥有堆值,rust中不允许两个指向相同内容的指针 //Rust在内存访问方面非常聪明,因此可以检测到竞争情况,因为两个变量指向同一个堆 println!("{:?}",v); }
所有权的思想是,只有一个变量绑定到资源,或者v绑定到资源或v2绑定到资源。
上面的例子抛出一个错误: borrow of moved value: `v`,这是因为资源的所有权已转移到v2,这意味着所有权从v移到v2(v2 = v),并且在移动后v无效。
将值传递给函数
当我们将堆中的对象传递给闭包或函数时,值的所有权也会发生变化。
fn main(){ let v = vec![1,2,3]; //向量v在堆中拥有对象 let v2 = v; //将所有权移至v2 display(v2); // v2移至显示状态,并且v2无效 println!("In main {:?}",v2); // v2在这里不再可用 } fn display(v:Vec<i32>){ println!("inside display {:?}",v); }
从函数返回值
传递给函数的所有权将在函数执行完成时失效,一种解决方法是让函数将拥有的对象返回给调用者。
fn main(){ let v = vec![1,2,3]; //向量v在堆中拥有对象 let v2 = v; //将所有权移至v2 let v2_return = display(v2); println!("In main {:?}",v2_return); } fn display(v:Vec<i32>)->Vec<i32> { //返回相同的向量 println!("inside display {:?}",v); }
所有权和原始类型
如果将一个基本类型变量中的内容复制到另一个变量中,所有权没有发生转移,这是因为原始变量比对象需要更少的资源。请考虑以下示例:
fn main(){ let u1 = 10; let u2 = u1; //将u1值复制(不移动)到u2 println!("u1 = {}",u1); }
输出为10。