[英]How can I reborrow a mutable reference without passing it to a function?
I have found a case where manually inlining a function changes the way the borrow-checker treats it, such that it no longer compiles. 我发现了一个案例,手动内联函数会改变借用检查器处理它的方式,使其不再编译。 Presumably it is relying on the information in the function signature.
据推测,它依赖于函数签名中的信息。 How can I provide this information in the inlined version?
如何在内联版本中提供此信息?
Let 'a
and 'b
be lifetimes with 'a
shorter than 'b
(which can be written 'b: 'a
). 设
'a
和'b
生命周期为'a
短于'b
(可以写成'b: 'a
)。
Suppose I have a p: &'b mut f32
. 假设我有一个
p: &'b mut f32
。 I can borrow p
briefly (with &mut p
) to obtain q: &'a mut &'b mut f32
. 我可以简单地借用
p
(用&mut p
)来获得q: &'a mut &'b mut f32
。
&'a mut &'b mut f32
is equivalent to &'a mut &'a mut f32
because 'b: 'a
? &'a mut &'b mut f32
等同于&'a mut &'a mut f32
因为'b: 'a
? I can then dereference q
(with *q
) to obtain r: &'a mut f32
. 然后我可以取消引用
q
(用*q
)来获得r: &'a mut f32
。 I can write to the f32
via r
(with *r = something
), and I can later (outside lifetime 'a
) read back the value via p
(with *p
). 我可以通过
r
(带*r = something
)写入f32
,然后我可以在(生命周期外的'a
)通过p
(带*p
)读回值。
Here is some working code that I think uses the above sequence: 以下是一些我认为使用上述顺序的工作代码:
fn reborrow<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
*q
}
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = reborrow(q);
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
(Replacing *q
with q
in the body of reborrow()
also works, because Rust inserts the necessary dereference if it is missing). (在
reborrow()
体中用q
替换*q
也有效,因为如果缺少必要的dereference,则会插入。
If I manually inline the reborrow()
call, it no longer compiles: 如果我手动内联
reborrow()
调用,它不再编译:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = *q; <-- ERROR REPORTED HERE.
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
error[E0507]: cannot move out of borrowed content
Who took away my toys? 谁带走了我的玩具? What is the type inference thinking/missing?
什么是类型推断思考/缺失?
Can I annotate the let
binding somehow to make the compiler infer the same types as in the previous version? 我能否以某种方式注释
let
绑定以使编译器推断出与先前版本相同的类型?
Here's another version that works, but which doesn't define the name r
: 这是另一个有效的版本,但没有定义名称
r
:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
**q = 2.718;
}
assert_eq!(*p, 2.718);
}
Here's a work-around that defines the name r
and works, but does not use the same sequence of borrows and dereferences: 这是一个定义名称
r
并且有效的解决方法,但不使用相同的借用和解除引用序列:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r = &mut **q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
I made a playground combining all four versions. 我做了一个结合所有四个版本的游乐场 。
The obvious solution works, as one could expect: 人们可以预期,显而易见的解决方案有效:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
It seems relatively intuitive and is what I would expect a newcomer to end up with. 它似乎相对直观,是我期望新人最终得到的。
If you start thinking about it, however, it will not make sense. 但是,如果你开始考虑它,它将没有意义。 As described, it looks like:
如上所述,它看起来像:
let r: &mut f32 = p;
moves out of p
p
p
later in assert_eq!(*p, 2.718);
assert_eq!(*p, 2.718);
使用p
assert_eq!(*p, 2.718);
A reasonable explanation would be that p
is Copy
, however it's not 1 ! 一个合理的解释是
p
是Copy
,但它不是1 !
The answer is that, implicitly, Rust is performing a re-borrowing behind the scenes. 答案是,Rust隐含地在幕后进行重新借用 。 That is, the explicit code is:
也就是说,显式代码是:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let r: &mut f32 = &mut *p;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
We can check this by attempting to read p
after re-borrowing it, and check the compiler error: 我们可以通过在重新借用后尝试读取
p
来检查这一点,并检查编译器错误:
error[E0502]: cannot borrow `p` as immutable because `*p` is also borrowed as mutable --> <anon>:6:24 | 5 | let r: &mut f32 = p; | - mutable borrow occurs here 6 | println!("{}", p); | ^ immutable borrow occurs here 7 | *r = 2.718; 8 | } | - mutable borrow ends here error: aborting due to previous error
Which confirms that p
is indeed only borrowed mutably, and not moved, cloned or copied. 这证实
p
确实只是可变地借用,而不是移动,克隆或复制。
1 A mutable reference cannot be Copy
or even Clone
as it would violate the Aliasing XOR Mutability principle which underpins Rust safety. 1 可变参考不能
Copy
甚至Clone
因为它会违反支持Rust安全性的混叠XOR可变性原则。
I can't possibly begin to explain this, but you can do a similar trick as the implicit dereference and say that r
is &mut f32
: 我不可能开始解释这一点,但你可以做一个与隐式解引用类似的技巧,并说
r
是&mut f32
:
fn main() {
let mut x: f32 = 3.142;
let mut p = &mut x;
{
let q = &mut p;
let r: &mut f32 = q;
*r = 2.718;
}
assert_eq!(*p, 2.718);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.