美文网首页
【RUST_BASIC】Rust 所有权

【RUST_BASIC】Rust 所有权

作者: ixiaolong | 来源:发表于2021-11-15 11:59 被阅读0次

    1 所有权规则

    • Rust 中的每一个值都有一个被称为其所有者(owner)的变量
    • 值在任一时刻有且只有一个所有者
    • 当所有者(变量)离开作用域,这个值将被丢弃

    2 内存与分配

    栈(stack)中的所有数据都必须占用已知且固定的大小,在编译时大小未知或大小可能变化的数据,要改为存储在堆(heap)上。

    入栈比在堆上分配内存要快,因为(入栈时)分配器无需为存储新数据去搜索内存空间;其位置总是在栈顶。相比之下,在堆上分配内存则需要更多的工作,这是因为分配器必须首先找到一块足够存放数据的内存空间,并接着做一些记录为下一次分配做准备。

    对于保存在堆上数据类型:

    • 必须在运行时向内存分配器(memory allocator)请求内存
    • 需要一个当我们处理完数据时将内存返回给分配器的方法

    Rust 可通过各自类型的方法进行内存的分配,例如 String 类型调用 String::from 即可进行内存的分配;其内存回收的策略是,内存在拥有它的变量离开作用域后就被自动释放:

    {
        let s = String::from("hello"); // 从此处起,s 是有效的
    
        // 使用 s
    }                                  // 此作用域已结束,
                                       // s 不再有效
    

    当变量离开作用域,Rust 在结尾的 } 调用一个drop函数释放 String 的内存。

    3 数据交互

    3.1 移动
    let s1 = String::from("hello");
    let s2 = s1;
    

    let s2 = s1 之后,Rust 认为 s1 不再有效,因此 Rust 不需要在 s1 离开作用域后清理任何东西,否则将会造成二次释放(double free)的错误。

    3.2 克隆
    let s1 = String::from("hello");
    let s2 = s1.clone();
    

    此后 s1 仍可继续使用。

    3.3 拷贝
    let x = 5;
    let y = x;
    

    在这里没有执行克隆操作,但 x 仍有效可继续使用,原因是像整型这样的在编译时已知大小的类型被整个存储在栈上,所以拷贝其实际的值是快速的。这意味着没有理由在创建变量 y 后使 x 无效。

    Rust 有一个叫做 Copy trait 的特殊注解,可以用在类似整型这样的存储在栈上的类型上,如果一个类型实现了 Copy trait,那么一个旧的变量在将其赋值给其他变量后仍然可用。另外,Rust 不允许自身或其任何部分实现了 Drop trait 的类型使用 Copy trait。

    任何一组简单标量值的组合都可以实现 Copy trait,任何不需要分配内存或某种形式资源的类型也都可以实现 Copy trait,如下是一些 Copy 的类型:

    • 所有整数类型,比如 u32。
    • 布尔类型,bool,它的值是 true 和 false。
    • 所有浮点数类型,比如 f64。
    • 字符类型,char。
    • 元组,当且仅当其包含的类型也都实现 Copy trait 的时候。比如,(i32, i32) 实现了 Copy,但 (i32, String) 就没有。

    4 引用

    引用符号为 &,允许使用值但不获取其所有权。

    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    

    &s1 语法创建了一个指向 s1 的引用,但是并不拥有它,所以当引用停止使用时,它所指向的值也不会被丢弃。创建一个引用的行为称为借用(borrowing)。

    引用默认不允许修改引用的值,添加 mut 的可变引用可修改引用的值:

    fn main() {
        let mut s = String::from("hello");
        change(&mut s);
    }
    
    fn change(some_string: &mut String) {
        some_string.push_str(", world");
    }
    

    另外,要避免悬垂引用(Dangling References)的出现,此时编译会报错:

    fn main() {
        let reference_to_nothing = dangle();
    }
    
    fn dangle() -> &String {
        let s = String::from("hello");
    
        &s
    }
    

    引用的规则如下:

    • 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用
    • 引用必须总是有效的

    5 slice

    slice 是一个没有所有权的数据类型 ,其允许引用集合中一段连续的元素序列,而不用引用整个集合。

    // 字符串slice
    let s = String::from("hello world");
    let hello = &s[0..5];
    let world = &s[6..11];
    
    // 数组slice
    let a = [1, 2, 3, 4, 5];
    let slice = &a[1..3];
    

    相关文章

      网友评论

          本文标题:【RUST_BASIC】Rust 所有权

          本文链接:https://www.haomeiwen.com/subject/ymqxtrtx.html