【发布时间】:2017-03-27 00:23:45
【问题描述】:
我发现手动内联函数会改变借用检查器处理它的方式,使其不再编译。大概它依赖于函数签名中的信息。如何在内联版本中提供这些信息?
我认为它是如何工作的
让'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绑定以使编译器推断与以前版本中相同的类型?
其他一些尝试
这是另一个有效的版本,但没有定义名称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 结合了所有四个版本。
【问题讨论】:
-
FWIW,根据您的
reborrow方法,我有一个 follow-up question。 -
@BurntSushi5 我也有类似的想法,但
{}技巧在这里不起作用,这似乎表明它在某种程度上有所不同。 -
@BurntSushi5 不过很有趣。 :-)
标签: rust borrow-checker