重新借用可变引用
Reborrowing of mutable reference
当我想知道可变引用如何移动到方法中时,所有的问题都开始了。
let a = &mut x;
a.somemethod(); // value of a should have moved
a.anothermethod(); // but it works.
我用谷歌搜索了很多。 (真的很多)
而且我注意到作为参数传递给函数的可变引用总是经历以下 t运行sformation。 (这叫做再借)
fn test(&mut a) -> ();
let a = &mut x;
test(a); // what we write in code.
test(&mut *a); // the actual action in code.
因此,我在谷歌上搜索了更多关于“再借”的详细信息。
这就是我得到的。
在任意代码中,x代表任意数据。我没有提到它,因为我认为它的类型对于讨论来说并不重要。 (不过,我自己用的是i32)。
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
很好。这很有趣。好像 b
不仅借了 x
还借了 a
.
也许,我们可以这样澄清再借:&'a *(&'b mut x)
。
它借用了 x
(这里有一个生命周期 'a),
但也借用了 a
(它的生命周期为 'b)。
所以我运行下面的代码来证实我的猜想
let x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
但这行得通!
什么??
但我只是决定得到这个。
&'a mut *&mutx
,不是 &'a mut *&'b mutx
。
我不知道为什么 mut x
在 &mut *&mutx
的生命周期内不可用,也不知道为什么 mut x
在 &mut *&mutx
的生命周期后重新可用,但是“好吧,就这么说吧。
但是看看这个。对于一个清晰和笼统的理解,这完全超出了我的想法。
let x: i32 = 1;
let b;
{
let a = &mut x;
let b = &**&a;
} // error!! a should live longer than b!
lifetime 不就是简单地依赖于真实数据 b
指的是什么吗???
&'a **& &mut x
,不是 &'a **&'b &'c mut x
。
然后呢??
&'a **&'b &mut x
??? (这是我的猜测)。
我该如何接受这种复杂的情况?
这些都是很好的问题!我会尽力回答我能回答的。
Rust 参考是寻找此类问题答案的好地方,关于 Rust 的深层语义。
首先,对于您关于方法解析的问题,参考资料
说:
When looking up a method call, the receiver may be automatically
dereferenced or borrowed in order to call a method. This requires a
more complex lookup process than for other functions, since there may
be a number of possible methods to call. The following procedure is
used:
The first step is to build a list of candidate receiver types. Obtain
these by repeatedly dereferencing the receiver
expression's type, adding each type encountered to the list, then
finally attempting an unsized coercion at the end, and adding the
result type if that is successful. Then, for each candidate T
, add
&T
and &mut T
to the list immediately after T
.
For instance, if the receiver has type Box<[i32;2]>
, then the
candidate types will be Box<[i32;2]>
, &Box<[i32;2]>
, &mut Box<[i32;2]>
, [i32; 2]
(by dereferencing), &[i32; 2]
, &mut [i32; 2]
, [i32]
(by unsized coercion), &[i32]
, and finally &mut [i32]
.
上面的 link 更详细。
对于您的其余问题,我认为这主要是关于类型强制的。 Some relevant coercions are:
&mut T
to &T
&T
or &mut T
to &U
if T
implements Deref<Target = U>
&mut T
to &mut U
if T
implements DerefMut<Target = U>
值得注意的是,&U
和 &mut U
都实现了 Deref<Target = U>
,&mut U
也实现了 DerefMut<Target = U>
。因此,second/third 规则导致以下强制转换:
Let T
be:
Coerce from
To
&U
&&U
&U
&U
&mut &U
&U
&mut U
&&mut U
&U
&mut U
&mut &mut U
&mut U
现在把参考文献拿开,让我们更详细地看看你的问题:
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
为了写入引用,它显然必须是可变的(又名唯一的)引用。当你写 let a = &mut x
时,现在 a
是访问 x
的唯一方法。现在当你写 let b = &mut *a
时,它实际上意味着 let b = &mut *(&mut x)
,它简化为 let b = &mut x
.
在这里,b
可变地借用了 a
,Rust 不会让你使用 a
,直到 b
被销毁……或者现在看来是这样。
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
这里,let b = &*a
变成let b = &*(&mut x)
,所以let b = &x
。不管b
是什么类型的引用,a
是一个可变引用,必须是唯一的,所以在b
消失(超出范围)之前你不能使用它。
let mut x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
(我假设你的意思是 let mut x
)。
现在有趣的地方来了。这里,由于 a
和 b
都可变地指向同一个对象,Rust 不会让你使用 a
直到 b
被销毁。似乎推理应该是,“因为 b
可变借用 a
”,但实际上并非如此。通常,b
实际上会借用 a
,对于像 Box
、std::cell::RefMut
等智能指针来说就是这种情况。但是,引用得到特殊处理:Rust 可以分析他们指向的内存。
所以当你写let b = &mut *a
时,b
实际上并没有借用a
!它只借用 a
指向的数据。这种区别以前不相关,但在这里它允许代码编译。
至于你的最后一个例子,我无法让它按照你描述的方式中断。
当我想知道可变引用如何移动到方法中时,所有的问题都开始了。
let a = &mut x;
a.somemethod(); // value of a should have moved
a.anothermethod(); // but it works.
我用谷歌搜索了很多。 (真的很多) 而且我注意到作为参数传递给函数的可变引用总是经历以下 t运行sformation。 (这叫做再借)
fn test(&mut a) -> ();
let a = &mut x;
test(a); // what we write in code.
test(&mut *a); // the actual action in code.
因此,我在谷歌上搜索了更多关于“再借”的详细信息。
这就是我得到的。
在任意代码中,x代表任意数据。我没有提到它,因为我认为它的类型对于讨论来说并不重要。 (不过,我自己用的是i32)。
let a = &mut x;
let b = &mut *a; // a isn't available from now on
*a = blahblah; // error! no more access allowed for a
*b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
let a = &mut x;
{
let b = &*a;
// *a = blahblah in this scope will throw an error, just like above case.
}
*a = blahblah; // but this works.
很好。这很有趣。好像 b
不仅借了 x
还借了 a
.
也许,我们可以这样澄清再借:&'a *(&'b mut x)
。
它借用了 x
(这里有一个生命周期 'a),
但也借用了 a
(它的生命周期为 'b)。
所以我运行下面的代码来证实我的猜想
let x: i32 = 1; // I wanted to make it clear that x lives in this scope.
let b;
{
let a = &mut x;
b = &mut *a;
}
*b = 0;
但这行得通!
什么??
但我只是决定得到这个。
&'a mut *&mutx
,不是 &'a mut *&'b mutx
。
我不知道为什么 mut x
在 &mut *&mutx
的生命周期内不可用,也不知道为什么 mut x
在 &mut *&mutx
的生命周期后重新可用,但是“好吧,就这么说吧。
但是看看这个。对于一个清晰和笼统的理解,这完全超出了我的想法。
let x: i32 = 1;
let b;
{
let a = &mut x;
let b = &**&a;
} // error!! a should live longer than b!
lifetime 不就是简单地依赖于真实数据 b
指的是什么吗???
&'a **& &mut x
,不是 &'a **&'b &'c mut x
。
然后呢??
&'a **&'b &mut x
??? (这是我的猜测)。
我该如何接受这种复杂的情况?
这些都是很好的问题!我会尽力回答我能回答的。
Rust 参考是寻找此类问题答案的好地方,关于 Rust 的深层语义。
首先,对于您关于方法解析的问题,参考资料 说:
When looking up a method call, the receiver may be automatically dereferenced or borrowed in order to call a method. This requires a more complex lookup process than for other functions, since there may be a number of possible methods to call. The following procedure is used:
The first step is to build a list of candidate receiver types. Obtain these by repeatedly dereferencing the receiver expression's type, adding each type encountered to the list, then finally attempting an unsized coercion at the end, and adding the result type if that is successful. Then, for each candidate
T
, add&T
and&mut T
to the list immediately afterT
.For instance, if the receiver has type
Box<[i32;2]>
, then the candidate types will beBox<[i32;2]>
,&Box<[i32;2]>
,&mut Box<[i32;2]>
,[i32; 2]
(by dereferencing),&[i32; 2]
,&mut [i32; 2]
,[i32]
(by unsized coercion),&[i32]
, and finally&mut [i32]
.
上面的 link 更详细。
对于您的其余问题,我认为这主要是关于类型强制的。 Some relevant coercions are:
&mut T
to&T
&T
or&mut T
to&U
ifT
implementsDeref<Target = U>
&mut T
to&mut U
ifT
implementsDerefMut<Target = U>
值得注意的是,&U
和 &mut U
都实现了 Deref<Target = U>
,&mut U
也实现了 DerefMut<Target = U>
。因此,second/third 规则导致以下强制转换:
Let T be: |
Coerce from | To |
---|---|---|
&U |
&&U |
&U |
&U |
&mut &U |
&U |
&mut U |
&&mut U |
&U |
&mut U |
&mut &mut U |
&mut U |
现在把参考文献拿开,让我们更详细地看看你的问题:
let a = &mut x; let b = &mut *a; // a isn't available from now on *a = blahblah; // error! no more access allowed for a *b = blahblah; // I've wrote this code not to confuse you of the lifetime of b. If not mentioned, it always live till the scope ends.
为了写入引用,它显然必须是可变的(又名唯一的)引用。当你写 let a = &mut x
时,现在 a
是访问 x
的唯一方法。现在当你写 let b = &mut *a
时,它实际上意味着 let b = &mut *(&mut x)
,它简化为 let b = &mut x
.
在这里,b
可变地借用了 a
,Rust 不会让你使用 a
,直到 b
被销毁……或者现在看来是这样。
let a = &mut x; { let b = &*a; // *a = blahblah in this scope will throw an error, just like above case. } *a = blahblah; // but this works.
这里,let b = &*a
变成let b = &*(&mut x)
,所以let b = &x
。不管b
是什么类型的引用,a
是一个可变引用,必须是唯一的,所以在b
消失(超出范围)之前你不能使用它。
let mut x: i32 = 1; // I wanted to make it clear that x lives in this scope. let b; { let a = &mut x; b = &mut *a; } *b = 0;
(我假设你的意思是 let mut x
)。
现在有趣的地方来了。这里,由于 a
和 b
都可变地指向同一个对象,Rust 不会让你使用 a
直到 b
被销毁。似乎推理应该是,“因为 b
可变借用 a
”,但实际上并非如此。通常,b
实际上会借用 a
,对于像 Box
、std::cell::RefMut
等智能指针来说就是这种情况。但是,引用得到特殊处理:Rust 可以分析他们指向的内存。
所以当你写let b = &mut *a
时,b
实际上并没有借用a
!它只借用 a
指向的数据。这种区别以前不相关,但在这里它允许代码编译。
至于你的最后一个例子,我无法让它按照你描述的方式中断。