变量绑定:移动 &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?
绝对没有,因为在这种情况下,这两个操作在语义上非常相似(如果 a
和 b
属于同一范围,则等效)。
- 要么将引用
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
可变地可用。
此代码在 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 ofa
intob
, but instead a "re"-borrow of*a
?What am I missing?
绝对没有,因为在这种情况下,这两个操作在语义上非常相似(如果 a
和 b
属于同一范围,则等效)。
- 要么将引用
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
可变地可用。