我发现了一个案例,手动内联一个函数会改变借用检查器对待它的方式,以至于它不再编译。据推测,它依赖于函数签名中的信息。我如何在内联版本中提供此信息?
我认为它是如何工作的
设 'a
和 'b
是 'a
比 'b
短的生命周期(可以是写成 'b: 'a
).
假设我有一个p: &'b mut f32
。我可以简单地借用 p
(使用 &mut p
)来获得 q: &'a mut &'b mut f32
。
- 我是否正确理解
&'a mut &'b mut f32
等同于&'a mut &'a mut f32
因为'b: 'a
?
然后我可以取消引用 q
(使用 *q
)以获得 r: &'a mut f32
。我可以通过 r
(使用 *r = something
)写入 f32
,我可以稍后(在生命周期之外 'a
) 通过p
(使用*p
)读回值。
使用函数调用
这是我认为使用上述序列的一些工作代码:
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);
}
(在 reborrow()
的主体中用 q
替换 *q
也可以,因为如果缺少必要的取消引用,Rust 会插入).
手动内联
如果我手动内联 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
谁拿走了我的玩具?什么是类型推断思维/缺失?
我能否以某种方式注释
let
绑定(bind)以使编译器推断出与以前版本相同的类型?
其他一些尝试
这是另一个有效的版本,但没有定义名称 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);
}
这里有一个解决方法,它定义了名称 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);
}
我做了一个playground结合所有四个版本。
最佳答案
正如人们所期望的那样,显而易见的解决方案有效:
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);
}
这看起来相对直观,也是我希望新手最终得到的结果。
但是,如果您开始考虑它,它就没有意义了。如前所述,它看起来像:
let r: &mut f32 = p;
将移出p
- 但我们稍后在
assert_eq!(*p, 2.718);
中使用了
p
一个合理的解释是p
是Copy
,但它不是1!
答案是,隐含地,Rust 正在幕后执行重新借用。即显式代码为:
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);
}
我们可以通过在重新借用后尝试读取 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
这证实 p
确实只是可变地借用,而不是移动、克隆或复制。
1 可变引用不能复制
甚至克隆
,因为它会违反支撑 Rust 安全性的别名 XOR 可变性原则.
关于rust - 如何在不将可变引用传递给函数的情况下重新借用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43036156/