Rust的借用检查器和早期返回

7

Rust编程语言沙盒链接

struct Foo {
    val: i32
}

impl Foo {
    pub fn maybe_get(&mut self) -> Option<&mut i32> {
        Some(&mut self.val)
    }
    
    pub fn definitely_get(&mut self) -> &mut i32 {
        { // Add closure to ensure things have a chance to get dropped
            if let Some(val) = self.maybe_get() {
                // Explicit return to avoid potential scope sharing with an else block or a match arms.
                return val;
            }
        }

        // One would think any mutable references would not longer be at play at this point

        &mut self.val   
    }
}

我有一些代码,它比上面提供的更加复杂,而且我已经努力解决了相当长一段时间。借用检查程序不满意definitely_get的实现,并出现以下错误:

error[E0499]: cannot borrow `self.val` as mutable more than once at a time
  --> src/main.rs:19:9
   |
10 |     pub fn definitely_get(&mut self) -> &mut i32 {
   |                           - let's call the lifetime of this reference `'1`
11 |         {
12 |             if let Some(val) = self.maybe_get() {
   |                                ---------------- first mutable borrow occurs here
13 |                 return val;
   |                        --- returning this value requires that `*self` is borrowed for `'1`
...
19 |         &mut self.val
   |         ^^^^^^^^^^^^^ second mutable borrow occurs here

似乎没有办法在可变引用中实现回退逻辑,这似乎是不合理的。我无法想象没有任何方法可以解决这个问题。

2
它可以与实验性的Polonius借用检查器一起使用(尝试使用cargo +nightly rustc -- -Zpolonius编译)。 - Chayim Friedman
2
这个回答解决了你的问题吗?为什么Rust认为借用在其他分支中仍然活跃 - Chayim Friedman
@ChayimFriedman,你能分享一段代码片段,让我知道如何重新组织以便编译吗?我尝试了许多不同的方法,但无法解决双重借用问题。 - quittle
2
这是一个作用域,而不是闭包。顺便说一句,你的观点仍然正确。 - GManNickG
1
我不想将它作为答案发布,因为很多初学者会误用它来解决合法错误,但是你可以通过指针逃逸来结束借用。查看 std::ptr::addr_of_mut。你需要使用一个不安全的块来实现这个操作,但在这种情况下是正确的。我有一些相当复杂的数据结构,也遇到了类似的问题,不幸的是。 - GManNickG
显示剩余2条评论
1个回答

0

我已经通过一种不幸昂贵的替代实现来解决这个问题,因为在我的非平凡示例中,maybe_get 的实现方式。

impl Foo {
    pub fn has_maybe_val(&self) -> bool {
        // Non-trivial lookup...
        true
    }

    pub fn maybe_get(&mut self) -> Option<&mut i32> {
        // Same non-trivial lookup...
        Some(&mut self.val)
    }
    
    pub fn definitely_get(&mut self) -> &mut i32 {
        if self.has_maybe_val() {
            self.maybe_get().unwrap() // Ouch!
        } else {
            &mut self.val
        } 
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接