kwo*_*yul 18 reference lifetime rust mutable-reference
当我想知道可变引用如何转移到方法中时,所有问题都开始了。
let a = &mut x;
a.somemethod(); // value of a should have moved
a.anothermethod(); // but it works.
Run Code Online (Sandbox Code Playgroud)
我用谷歌搜索了很多。(真的很多)而且我注意到作为参数传递给函数的可变引用总是会经历以下转换。(这称为再借)
fn test(&mut a) -> ();
let a = &mut x;
test(a); // what we write in code.
test(&mut *a); // the actual action in code.
Run Code Online (Sandbox Code Playgroud)
因此,我在谷歌上搜索了更多有关“再借”的详细信息。
这就是我所拥有的。
在任何代码中,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.
Run Code Online (Sandbox Code Playgroud)
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.
Run Code Online (Sandbox Code Playgroud)
那么好吧。这很有趣。看来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;
Run Code Online (Sandbox Code Playgroud)
但这有效!
什么??但我刚刚决定得到这个。
&'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!
Run Code Online (Sandbox Code Playgroud)
寿命不就是仅仅依赖于真实数据b所指的吗???
&'a **& &mut x, 不是&'a **&'b &'c mut x。
现在怎么办?
&'a **&'b &mut x??? (这是我的猜测)。
我该如何接受这个复杂的局面呢?
Cod*_*256 12
这些都是一些很好的问题!我会尽力回答我能回答的问题。
Rust 参考是寻找此类问题的答案的好地方,有关 Rust 的更深层次语义。
首先,对于您关于方法解析的问题,参考文献说:
当查找方法调用时,接收者可能会自动取消引用或借用以调用方法。这需要比其他函数更复杂的查找过程,因为可能有许多可能的方法可供调用。使用以下过程:
第一步是建立候选接收者类型列表。通过重复取消引用接收者表达式的类型,将遇到的每种类型添加到列表中,最后在最后尝试未调整大小的强制转换,如果成功则添加结果类型来获取这些类型。然后,对于每个候选者
T,将&T和&mut T立即添加到列表中的 后面T。例如,如果接收者的类型为
Box<[i32;2]>,则候选类型将为Box<[i32;2]>、&Box<[i32;2]>、&mut Box<[i32;2]>、[i32; 2](通过解引用)、&[i32; 2]、&mut [i32; 2]、[i32](通过未调整大小的强制)、&[i32]、 最后&mut [i32]。
上面的链接有更详细的介绍。
对于您的其余问题,我认为这主要与类型强制有关。一些相关的强制是:
&mut T到&T&T或&mut T如果实现&UTDeref<Target = U>&mut T如果实现&mut UTDerefMut<Target = U>
值得注意的是,&U既&mut U实现了Deref<Target = U>,&mut U也实现了DerefMut<Target = U>。因此,第二/第三条规则导致以下强制:
设T: |
强制来自 | 到 |
|---|---|---|
&U |
&&U |
&U |
&U |
&mut &U |
&U |
&mut U |
&&mut U |
&U |
&mut U |
&mut &mut U |
&mut U |
现在,参考资料已经完成,让我们更详细地看看您的问题:
Run Code Online (Sandbox Code Playgroud)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被销毁......或者目前看来是这样。
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)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智能指针来说就是这种情况。但是,引用得到特殊处理:Rust 可以分析它们指向的内存。Boxstd::cell::RefMut
所以当你写的时候let b = &mut *a,b实际上并不是借a!它仅借用数据a点。这种区别以前并不相关,但在这里它允许代码编译。
至于你的最后一个例子,我无法让它按照你描述的方式打破。
| 归档时间: |
|
| 查看次数: |
4112 次 |
| 最近记录: |