Rust - 所有权

  • 简述

    程序的内存可以按以下方式分配 -
    • Stack(栈)
    • Heap(堆)
  • Stack(栈)

    堆栈遵循后进先出的顺序。堆栈存储在编译时大小已知的数据值。例如,固定大小 i32 的变量是堆栈分配的候选对象。它的大小在编译时是已知的。所有标量类型都可以存储在堆栈中,因为大小是固定的。
    考虑一个字符串的例子,它在运行时被赋值。在编译时无法确定此类字符串的确切大小。所以它不是堆栈分配的候选者,而是堆分配的候选者。

    Heap(堆)

    堆内存存储在编译时大小未知的数据值。它用于存储动态数据。简单地说,堆内存被分配给在程序的整个生命周期中可能会改变的数据值。与堆栈相比,堆是内存中组织较少的区域。
  • 什么是所有权?

    Rust 中的每个值都有一个变量,称为 owner的值。存储在 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绑定到资源。上面的例子抛出一个错误 -使用移动的值:`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。