rust 教程 02 所有权与move
所有权
每个值都有一个唯一的owner来决定它的lifetime;当owner被drop时,owned value将会被drop。一个变量拥有它的值;当控制离开声明这个变量的block时,这个变量将被drop,同时值也被drop。owners和owned values形成tree,rust中的每个值都是某个树的成员。
rust同时也扩展了所有权的概念:
- 可以将值从一个owner move给另一个
- 非常简单的类型将不会收到所有权的约束,即
Copy
类型 - 标准库也提供了引用计数的类型
Rc
和Arc
可以使得值可以拥有多个onwers - 可以借用一个值的引用; ref是非owning的指针,受到lifetime的限制
Moves
在rust中,像类似给一个变量赋一个值,将它传给函数,或者从函数返回值都不会拷贝这个值,而是move这个值。目标将继续控制值的lifetime。如果想进行深拷贝,我们可能需要调用clone
方法。
如果将一个值赋给已经初始化的变量,变量原有值将被drop;给函数传递参数,也会将所有权move给函数参数中;从函数返回值会将所有权move给caller。这种move看上去可能不是高效,但rust提供以下两种机制:
- move指移动value proper,而不是相应的堆存储
- 编译器可以直接观察所有的move,生成对应的优化代码
move 和控制流
如果变量在进行条件判断后,仍拥有其值,那么我们可以其内部使用这个变量。
move和索引内容
注意一般来说,我们不能直接将value从某个vector中移出,例如
let v = vec!["1".to_string(),"2".to_string(),"3".to_string()];
let first = v[0]; // error
有以下三种可能的解法:
// 1. pop the last element
let last = v.pop().expect("empty");
// 2. 与最后一个元素交换位置
let second = v.swap_removed(1);
// 3. 将特定的值移入空位
let third = std::mem::replace(&mut v[2], "s".to_string());
注意像vec的集合类型,可以在for循环中消耗整个集合:
for mut s in v {
//
}
如果说真的需要移出一个值,可以使用Option来作为某种占位符:
struct Person {name: Option<String> }
let mut composers = Vec::new();
// ...
let first_name = std::mem::replace(&mut composers[0].name, None);
// or
let first_name = composers[0].name.take();
Copy类型:Move的例外情况
标准的copy类型包括:整型 浮点型 bool char; 以及 copy类型的数组和元组
有一个原则是,当值被drop时需要做一些别的事情都不能是copy类型。
用户定义的类型(struct & enum)是copy类型吗? 默认来说不是。我们可以通过添加 #[derive(Copy, Clone)]
来让这个类型成为copy类型,当然field必须都是copy类型
Rc和Arc: 共享所有权
Arc是线程安全的。
use std::rc::Rc;
let s = Rc::new("hello".to_string());
let t = s.clone();
let u = s.clone();
注意Rc指针拥有的值需要是不可变的。