【发布时间】:2021-12-09 07:03:53
【问题描述】:
我遇到了一个 Rust 借用检查器错误,我认为这是 non-lexical lifetimes 当前实现的限制。我想写的代码是这样的:
struct Thing {
value: i32
}
impl Thing {
fn value(&self) -> &i32 {
&self.value
}
fn increment(&mut self) {
self.value += 1;
}
}
/// Increments the value of `thing` if it is odd, and returns a reference to the value.
fn increment_if_odd(thing: &mut Thing) -> &i32 {
let ref_to_value = thing.value();
if (*ref_to_value % 2) == 0 {
return ref_to_value;
}
thing.increment(); // fails to compile because the immutable borrow `ref_to_value` is still alive
thing.value()
}
第一个问题:我是否认为这段代码是 100% 安全的,而借用检查器过于保守?返回ref_to_value 的分支不会改变thing,因此保证引用是有效的,而另一个分支根本不使用ref_to_value。 (我知道如果我用return thing.value(); 替换return ref_to_value; 它将编译,但在我的实际代码中value 方法很昂贵。)
看来我可以通过指针“清洗”引用来解决这个问题:
if (*ref_to_value % 2) == 0 {
return unsafe {
&*(ref_to_value as *const i32)
}
}
第二个问题:这很安全吗?我以前从来没有用过 unsafe 所以我很紧张。
我猜第三个问题:有没有办法用安全的 Rust 重写它?约束是 value 只能在非变异路径上调用一次。
【问题讨论】:
-
我想说编译器在这里有问题。因为通过强制执行额外的 escope,应该删除引用。但我不是。 play.rust-lang.org/…
-
即使显式删除也不起作用:play.rust-lang.org/…
-
看看the RFC for non-lexical lifetimes。第三个例子和你的差不多,第四个的变通方法可以修改。
-
这不是编译器错误,而是已知限制。我知道我们有这个问题的多个重复项,但我现在无法找到一个。我会继续挖掘。
-
我想用 Polonius 补充一下,有问题的代码已经编译了 - play.rust-lang.org/…。
标签: rust unsafe borrow-checker