所有权和移动

因为变量要负责释放它们拥有的资源,所以资源只能拥有一个所有者。这也防止了资源的重复释放。注意并非所有变量都拥有资源(例如引用)。

在进行赋值(let x = y)或通过值来传递函数参数(foo(x))的时候,资源的所有权(ownership)会发生转移。按照 Rust 的说法,这被称为资源的移动(move)。

在移动资源之后,原来的所有者不能再被使用,这可避免悬挂指针(dangling pointer)的产生。

  1. // 此函数取得堆分配的内存的所有权
  2. fn destroy_box(c: Box<i32>) {
  3. println!("Destroying a box that contains {}", c);
  4. // `c` 被销毁且内存得到释放
  5. }
  6. fn main() {
  7. // 栈分配的整型
  8. let x = 5u32;
  9. // 将 `x` *复制*到 `y`——不存在资源移动
  10. let y = x;
  11. // 两个值各自都可以使用
  12. println!("x is {}, and y is {}", x, y);
  13. // `a` 是一个指向堆分配的整数的指针
  14. let a = Box::new(5i32);
  15. println!("a contains: {}", a);
  16. // *移动* `a` 到 `b`
  17. let b = a;
  18. // 把 `a` 的指针地址(而非数据)复制到 `b`。现在两者都指向
  19. // 同一个堆分配的数据,但是现在是 `b` 拥有它。
  20. // 报错!`a` 不能访问数据,因为它不再拥有那部分堆上的内存。
  21. //println!("a contains: {}", a);
  22. // 试一试 ^ 去掉此行注释
  23. // 此函数从 `b` 中取得堆分配的内存的所有权
  24. destroy_box(b);
  25. // 此时堆内存已经被释放,这个操作会导致解引用已释放的内存,而这是编译器禁止的。
  26. // 报错!和前面出错的原因一样。
  27. //println!("b contains: {}", b);
  28. // 试一试 ^ 去掉此行注释
  29. }