【RUST_BASIC】Rust 所有权

2021-11-15  本文已影响0人  ixiaolong

1 所有权规则

2 内存与分配

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

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

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

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 的类型:

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];
上一篇下一篇

猜你喜欢

热点阅读