Rust - 所有权



程序的内存可以按以下方式分配:

栈遵循后进先出的顺序。栈存储大小在编译时已知的数据值。例如,大小固定的变量 i32 是栈分配的候选者。它的尺寸在编译时已知。所有标量类型都可以存储在栈中,因为其大小是固定的。

考虑一个在运行时赋值的字符串的例子。此类字符串的确切大小在编译时无法确定。因此,它不是栈分配的候选者,而是堆分配的候选者。

堆内存存储大小在编译时未知的数据值。它用于存储动态数据。简单来说,堆内存分配给在程序生命周期中可能发生变化的数据值。与栈相比,堆是内存中组织性较差的区域。

什么是所有权?

Rust 中的每个值都有一个被称为该值所有者的变量。Rust 中存储的每个数据都将有一个与其关联的所有者。例如,在语法let age = 30;中,age是值30的所有者。

  • 每个数据一次只能拥有一个所有者。

  • 两个变量不能指向同一个内存位置。变量将始终指向不同的内存位置。

转移所有权

可以通过以下方式转移值的所有权:

  • 将一个变量的值赋给另一个变量。

  • 将值传递给函数。

  • 从函数返回值。

将一个变量的值赋给另一个变量

Rust 作为一门语言的关键卖点是其内存安全性。内存安全是通过严格控制谁可以使用什么以及何时使用限制来实现的。

考虑以下代码片段:

fn main(){
   let v = vec![1,2,3]; 
   // vector v owns the object in heap

   //only a single variable owns the heap memory at any given time
   let v2 = v; 
   // here two variables owns heap value,
   //two pointers to the same content is not allowed in rust

   //Rust is very smart in terms of memory access ,so it detects a race condition
   //as two variables point to same heap

   println!("{:?}",v);
}

上面的例子声明了一个向量 v。所有权的概念是只有一个变量绑定到一个资源,要么v绑定到资源,要么v2绑定到资源。上面的例子会抛出一个错误:use of moved value: `v`。这是因为资源的所有权被转移到了 v2。这意味着所有权从 v 转移到 v2 (v2=v),并且 v 在移动后无效。

将值传递给函数

当我们将堆中的对象传递给闭包或函数时,值的所有权也会发生变化。

fn main(){
   let v = vec![1,2,3];     // vector v owns the object in heap
   let v2 = v;              // moves ownership to v2
   display(v2);             // v2 is moved to display and v2 is invalidated
   println!("In main {:?}",v2);    //v2 is No longer usable here
}
fn display(v:Vec<i32>){
   println!("inside display {:?}",v);
}

从函数返回值

传递给函数的所有权将在函数执行完成后失效。解决此问题的一种方法是让函数将拥有对象返回给调用者。

fn main(){
   let v = vec![1,2,3];       // vector v owns the object in heap
   let v2 = v;                // moves ownership to v2
   let v2_return = display(v2);    
   println!("In main {:?}",v2_return);
}
fn display(v:Vec<i32>)->Vec<i32> { 
   // returning same vector
   println!("inside display {:?}",v);
}

所有权和原始类型

对于原始类型,一个变量的内容被复制到另一个变量。因此,不会发生所有权移动。这是因为原始变量比对象需要的资源更少。考虑以下示例:

fn main(){
   let u1 = 10;
   let u2 = u1;  // u1 value copied(not moved) to u2

   println!("u1 = {}",u1);
}

输出将是 – 10。

广告