rust 教程 02 所有权与move

所有权

每个值都有一个唯一的owner来决定它的lifetime;当owner被drop时,owned value将会被drop。一个变量拥有它的值;当控制离开声明这个变量的block时,这个变量将被drop,同时值也被drop。owners和owned values形成tree,rust中的每个值都是某个树的成员。

rust同时也扩展了所有权的概念:

  • 可以将值从一个owner move给另一个
  • 非常简单的类型将不会收到所有权的约束,即 Copy类型
  • 标准库也提供了引用计数的类型 RcArc 可以使得值可以拥有多个onwers
  • 可以借用一个值的引用; ref是非owning的指针,受到lifetime的限制

Moves

在rust中,像类似给一个变量赋一个值,将它传给函数,或者从函数返回值都不会拷贝这个值,而是move这个值。目标将继续控制值的lifetime。如果想进行深拷贝,我们可能需要调用clone方法。

如果将一个值赋给已经初始化的变量,变量原有值将被drop;给函数传递参数,也会将所有权move给函数参数中;从函数返回值会将所有权move给caller。这种move看上去可能不是高效,但rust提供以下两种机制:

  1. move指移动value proper,而不是相应的堆存储
  2. 编译器可以直接观察所有的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指针拥有的值需要是不可变的。

posted @ 2025-03-21 17:58  xwher  阅读(75)  评论(0)    收藏  举报