变量绑定:移动 &mut 还是借用引用对象?

Variable binding: moving a &mut or borrowing the referent?

此代码在 let c = a; 处按预期失败,编译错误 "use of moved value: a":

fn main() {
    let a: &mut i32 = &mut 0;
    let b = a;
    let c = a;
}

a 已移入 b,无法再分配给 c。到目前为止,还不错。

但是,如果我只注释 b 的类型而不管其他的:

fn main() {
    let a: &mut i32 = &mut 0;
    let b: &mut i32 = a;
    let c = a;
}

代码在 let c = a;

再次失败

但这次有一个非常不同的错误消息:"cannot move out of a because it is borrowed ... borrow of *a occurs here: let b: &mut i32 = a;"

所以,如果我只是注释 b 的类型:没有将 a 移动到 b,而是 "re"-借用 *a?

我错过了什么?

干杯。

So, if I just annotate b's type: no move of a into b, but instead a "re"-borrow of *a?

What am I missing?

绝对没有,因为在这种情况下,这两个操作在语义上非常相似(如果 ab 属于同一范围,则等效)。

  • 要么将引用 a 移动到 b,使 a 成为移动值,不再可用。
  • 要么在 b 中重新借用 *a,只要 b 在范围内,a 就无法使用。

第二种情况不如第一种情况明确,您可以通过将定义 b 的行放入子范围来显示这一点。

此示例无法编译,因为 a 已移动:

fn main() {
    let a: &mut i32 = &mut 0;
    { let b = a; }
    let c = a;
}

但是这个会,因为一旦 b 超出范围 a 就会解​​锁:

fn main() {
    let a: &mut i32 = &mut 0;
    { let b = &mut *a; }
    let c = a;
}

现在,对于“为什么注释 b 的类型会改变行为?”这个问题,我的猜测是:

  • 在没有类型注解的情况下,操作简单明了。什么都不需要检查。
  • 当有类型注释时,可能需要转换(将 &mut _ 转换为 &_,或将简单引用转换为对特征对象的引用)。因此编译器选择重新借用该值,而不是移动。

例如,这段代码完全有效:

fn main() {
    let a: &mut i32 = &mut 0;
    let b: &i32 = a;
}

并且在这里将 a 移动到 b 没有任何意义,因为它们属于不同的类型。这段代码仍然可以编译:b 只是重新借用 *a,只要 b 在范围内,该值就不会通过 a 可变地可用。