为什么可变引用没有移到这里?
Why is the mutable reference not moved here?
我的印象是可变引用(即 &mut T
)总是被移动。这是完全有道理的,因为它们允许独占可变访问。
在下面的代码中,我将一个可变引用分配给另一个可变引用,并移动了原始引用。结果我不能再使用原来的了:
let mut value = 900;
let r_original = &mut value;
let r_new = r_original;
*r_original; // error: use of moved value *r_original
如果我有这样的函数:
fn make_move(_: &mut i32) {
}
并将我的原始示例修改为如下所示:
let mut value = 900;
let r_original = &mut value;
make_move(r_original);
*r_original; // no complain
我希望在调用函数 make_move
时移动可变引用 r_original
。然而,这并没有发生。通话后我仍然可以使用参考。
如果我使用通用函数make_move_gen
:
fn make_move_gen<T>(_: T) {
}
并这样称呼它:
let mut value = 900;
let r_original = &mut value;
make_move_gen(r_original);
*r_original; // error: use of moved value *r_original
再次移动引用,因此程序的行为符合我的预期。
为什么调用函数时引用没有移动make_move
?
我按照这些思路问了一些问题 。
似乎在某些(很多?)情况下,不是移动,而是重新借用。没有违反内存安全,只有 "moved" 值还在。我也找不到关于该行为的任何文档。
@Levans 提出了一个 github 问题 here,尽管我不完全相信这只是一个文档问题:可靠地移出 &mut 引用似乎是 Rust 所有权方法的核心。
这实际上可能是一个很好的理由。
&mut T
实际上 不是一种类型:所有借用都由一些(可能无法表达的)生命周期参数化。
写的时候
fn move_try(val: &mut ()) {
{ let new = val; }
*val
}
fn main() {
move_try(&mut ());
}
类型推断引擎推断typeof new == typeof val
,因此它们共享原始生命周期。这意味着从 new
借用直到从 val
借用才结束。
这意味着它等同于
fn move_try<'a>(val: &'a mut ()) {
{ let new: &'a mut _ = val; }
*val
}
fn main() {
move_try(&mut ());
}
但是,当你写
fn move_try(val: &mut ()) {
{ let new: &mut _ = val; }
*val
}
fn main() {
move_try(&mut ());
}
转换发生 - 与让您放弃指针可变性的事情相同。这意味着生命周期是一些(看似无法指定)'b < 'a
。这涉及演员表,因此涉及再借,因此再借可能超出范围。
总是重新借用的规则可能会更好,但显式声明不会有太大问题。
是implicit reborrow
。这个话题不是 well documented.
这个问题已经回答的很好了:
- how implicit reborrow works
- how reborrow works along with borrow split
如果我稍微调整一下通用的,它也不会抱怨
fn make_move_gen<T>(_: &mut T) {
}
或
let _ = *r_original;
我的印象是可变引用(即 &mut T
)总是被移动。这是完全有道理的,因为它们允许独占可变访问。
在下面的代码中,我将一个可变引用分配给另一个可变引用,并移动了原始引用。结果我不能再使用原来的了:
let mut value = 900;
let r_original = &mut value;
let r_new = r_original;
*r_original; // error: use of moved value *r_original
如果我有这样的函数:
fn make_move(_: &mut i32) {
}
并将我的原始示例修改为如下所示:
let mut value = 900;
let r_original = &mut value;
make_move(r_original);
*r_original; // no complain
我希望在调用函数 make_move
时移动可变引用 r_original
。然而,这并没有发生。通话后我仍然可以使用参考。
如果我使用通用函数make_move_gen
:
fn make_move_gen<T>(_: T) {
}
并这样称呼它:
let mut value = 900;
let r_original = &mut value;
make_move_gen(r_original);
*r_original; // error: use of moved value *r_original
再次移动引用,因此程序的行为符合我的预期。
为什么调用函数时引用没有移动make_move
?
我按照这些思路问了一些问题
似乎在某些(很多?)情况下,不是移动,而是重新借用。没有违反内存安全,只有 "moved" 值还在。我也找不到关于该行为的任何文档。
@Levans 提出了一个 github 问题 here,尽管我不完全相信这只是一个文档问题:可靠地移出 &mut 引用似乎是 Rust 所有权方法的核心。
这实际上可能是一个很好的理由。
&mut T
实际上 不是一种类型:所有借用都由一些(可能无法表达的)生命周期参数化。
写的时候
fn move_try(val: &mut ()) {
{ let new = val; }
*val
}
fn main() {
move_try(&mut ());
}
类型推断引擎推断typeof new == typeof val
,因此它们共享原始生命周期。这意味着从 new
借用直到从 val
借用才结束。
这意味着它等同于
fn move_try<'a>(val: &'a mut ()) {
{ let new: &'a mut _ = val; }
*val
}
fn main() {
move_try(&mut ());
}
但是,当你写
fn move_try(val: &mut ()) {
{ let new: &mut _ = val; }
*val
}
fn main() {
move_try(&mut ());
}
转换发生 - 与让您放弃指针可变性的事情相同。这意味着生命周期是一些(看似无法指定)'b < 'a
。这涉及演员表,因此涉及再借,因此再借可能超出范围。
总是重新借用的规则可能会更好,但显式声明不会有太大问题。
是implicit reborrow
。这个话题不是 well documented.
这个问题已经回答的很好了:
- how implicit reborrow works
- how reborrow works along with borrow split
如果我稍微调整一下通用的,它也不会抱怨
fn make_move_gen<T>(_: &mut T) {
}
或
let _ = *r_original;