简介
在本实验中,将解释在 Rust 中,变量拥有资源的所有权,并且只能有一个所有者,这可防止资源被多次释放。当通过值来赋值变量或传递函数参数时,资源的所有权会被转移,这称为移动。移动之后,先前的所有者不能再使用,以避免创建悬空指针。代码示例通过展示栈分配和堆分配变量的所有权如何转移,以及在变量所有权被移动后访问该变量如何导致错误,来演示这些概念。
注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用
main.rs,并通过rustc main.rs &&./main来编译和运行它。
所有权与移动
由于变量负责释放其自身的资源,资源只能有一个所有者。这也可防止资源被释放多次。请注意,并非所有变量都拥有资源(例如,[引用])。
在进行赋值(let x = y)或按值传递函数参数(foo(x))时,资源的所有权会被转移。在 Rust 中,这被称为移动。
在移动资源之后,先前的所有者不能再被使用。这可避免创建悬空指针。
// 此函数获取堆分配内存的所有权
fn destroy_box(c: Box<i32>) {
println!("Destroying a box that contains {}", c);
// `c` 被销毁且内存被释放
}
fn main() {
// 栈分配的整数
let x = 5u32;
// 将 `x` **复制** 到 `y` - 没有资源被移动
let y = x;
// 两个值都可以独立使用
println!("x is {}, and y is {}", x, y);
// `a` 是指向堆分配整数的指针
let a = Box::new(5i32);
println!("a contains: {}", a);
// 将 `a` **移动** 到 `b`
let b = a;
// `a` 的指针地址被复制(而非数据)到 `b` 中。
// 两者现在都是指向同一堆分配数据的指针,但
// `b` 现在拥有它。
// 错误!`a` 不能再访问数据,因为它不再拥有
// 堆内存
//println!("a contains: {}", a);
// TODO ^ 尝试取消注释此行
// 此函数从 `b` 获取堆分配内存的所有权
destroy_box(b);
// 由于此时堆内存已被释放,此操作将
// 导致解引用已释放的内存,但这被编译器禁止
// 错误!与上一个错误原因相同
//println!("b contains: {}", b);
// TODO ^ 尝试取消注释此行
}
总结
恭喜你!你已完成“所有权与移动”实验。你可以在 LabEx 中练习更多实验以提升你的技能。