===^^===
《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用:
在Rust中,所有权这个概念内置于语言本身,并通过编译期检查强制执行。每个值都有决定其生命周期的唯一拥有者,当拥有者被释放时,它拥有的值也会同时被释放。
在Rust中,释放被称为丢弃(drop)。
Box<T>是指向存储在堆上的T类型值的指针。因为Box拥有它所指向的空间,所以当丢弃Box是,也会释放此空间:
{
let point = Box::new((0.5, 1.5)); // 在此分配了point
let label = format!("{:?}", point); // 在此分配了label
assert_eq(label, "(0.5, 1.5)"); // 在此全部丢弃了
}
拥有者及其拥有的那些值形成了一棵树:值的拥有者是值的父节点,值拥有的值是值的子节点。每棵树的总根都是一个变量,当该变量超出作用域时,整棵树都将消失。
Rust的单一拥有者规则将禁止任何可能让它们排列得比树结构更复杂的可能性。
所以,Rust确实不如其它语言强大,其它所有实用的编程语言都能构建出任意复杂的对象图。
Rc和Arc允许值在某些限制下有多个拥有者。
在Rust中,对大多数类型来说,为变量赋值、将其传给函数或从函数返回这样的操作,都不会复制值,而是会移动值。源会把值的所有权转移给目标并变回未初始化状态,改由目标变量来控制值的生命周期。
调用向量的clone方法,该方法会执行向量及其元素的深拷贝。
将参数传给函数会将所有权转移给函数的参数、从函数返回一个值会将所有权转移给调用者、构建元组会将值转移给元组。
移动的永远是值本身,而不是这些值拥有的堆存储。对于向量和字符串,值本身就是指单独的"三字标头"。
移动与控制流:
示例1
let x = vec!10, 20, 30;
if c {
f(x); // 移动x
} else {
g(x); // 移动x
}
h(x); // 错误,只要任何一条路径移动了x的所有权,x在这里就是未初始化的
示例2
let x = vec!10, 20, 30;
while f() {
g(x); // 错误,x已经在第一次迭代中被移动给函数g了
}
示例3
let mut x = vec!10, 20, 30;
while f() {
g(x);
x = h(); // x被赋予了新值,因此该循环可以正确执行
}
let mut v = vec!10, 20, 30;
let x = v2; // 错误,不能移动到Vec索引结构之外
将向量直接传给循环(例如for ... in v)时,会将向量从v中移动出去,让v变成未初始化转态。
标准Copy类型包括所有整型、浮点型、char类型和boolean类型。Copy类型的元组或固定大小的数组本身也是Copy类型。
String不是Copy类型,因为它拥有从堆中分配的缓冲区。Box<T>也不是Copy类型,因为它拥有从堆中分配的引用目标。File类型不是Copy类型,因为复制它需要向操作系统申请另一个文件句柄。
任何在丢弃值时需要做一些特殊操作的类型都不能是Copy类型:Vec需要释放自身元素、File需要关闭自身文件句柄、MutexGuard需要解锁自身互斥锁。
默认情况下,struct和enum都不是Copy类型。如果此结构体的所有字段本身都是copy类型,可以通过将属性#derive(Copy, Clone)放置在此定义之上来创建Copy类型:
#derive(Copy, Clone)
struct Label {number: u32}
试图在一个其字段不全是Copy类型的结构体上这样做,会触发编译错误。
Rc<T>值是指向附带引用计数的在堆上分配的T型指针。克隆Rc<T>值并不会复制T,只会创建另一个指向它的指针并递增引用计数。
let s: Rc<String> = Rc::new("abc".to_string());
Let t: Rc<String> = s.clone();
所有权规则适用于Rc指针本身,当丢弃最后一个现有Rc时,Rust也会丢弃T。
s.push_str("def"); // 错误,因为Rc指针拥有的值是不可变的。
Rust的内存和线程安全保证的基石是:确保不会有任何值时既共享又可变的。Rust制定Rc指针的引用目标通常都可以共享,因此就不能是可变的。
如果有两个引用计数的值是先相互指向的,那么其中一个值就会让另一个值的引用计数保持在0以上,因此这些值将永远不被释放。
===^^===
《榴芒客服系统》是我们工作室开发的在线客服系统,欢迎下载试用: