【问题标题】:cannot borrow as immutable because it is also borrowed as mutable不能借用为不可变的,因为它也可以借用为可变的
【发布时间】:2016-01-28 06:38:23
【问题描述】:

我正在使用库中的结构 FooBar,但在客户端代码中出现编译错误。我将代码简化为:

use std::marker::PhantomData;

struct Foo {
    some_str: &'static str,
}

struct Bar<'a> {
    some_str: &'static str,
    marker: PhantomData<&'a Foo>,
}

impl Foo {
    fn read_data(&self) {
        // add code here
    }
    fn create_bar<'a>(&'a mut self) -> Bar<'a> {
        Bar {
            some_str: "test2",
            marker: PhantomData,
        }
    }
}

fn process(_arr: &mut [Bar]) {}

fn main() {
    let mut foo = Foo { some_str: "test" };
    let mut array: [Bar; 1] = [foo.create_bar()];
    process(&mut array);
    foo.read_data();
}

(playground)

输出:

error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
  --> src/main.rs:30:5
   |
28 |     let mut array: [Bar; 1] = [foo.create_bar()];
   |                                --- mutable borrow occurs here
29 |     process(&mut array);
30 |     foo.read_data();
   |     ^^^ immutable borrow occurs here
31 | }
   | - mutable borrow ends here

控制台输出中的错误很清楚,但我无法解决问题。

【问题讨论】:

    标签: rust


    【解决方案1】:

    您可以通过将 array 变量放置在带有花括号 ({ ... }) 的新范围内来限制其生命周期:

    fn main() {
        let mut foo = Foo { some_str: "test" };
        {
            let mut array: [Bar; 1] = [foo.create_bar()];
            process(&mut array);
        }
        foo.read_data();
    }
    

    【讨论】:

    • 是否可以明确指定变量 'foo' 的寿命比不带括号的数组变量长?
    • 不,我认为这不可能。
    • 看起来有一些借用检查器错误。 Bar 结构包含对 Foo 的不可变引用,但 Rust 认为 foo 被借用为可变的。
    • @aSpex create_bar 采用&amp;'a mut self:这就是可变借用 foo 的原因。即使在此示例中您实际上根本没有使用self'a 的生命周期将从分配给arrayarray 超出范围的那一刻。使用括号可以限制array 的范围并结束可变借用。正在进行添加“非词法生命周期”的工作,这将使 Rust 足够聪明,可以自己找出 'a 在这种情况下实际上不需要走到函数的末尾,因为 array 不是 foo.read_data之后使用
    • @aSpex limits of lifetimes 在 Rustonomicon 中更详细地介绍了这一点
    【解决方案2】:

    默认启用non-lexical lifetimes 后,您的原始代码将按原样运行:

    #![feature(nll)]
    
    use std::marker::PhantomData;
    
    struct Foo {
        some_str: &'static str,
    }
    
    struct Bar<'a> {
        some_str: &'static str,
        marker: PhantomData<&'a Foo>,
    }
    
    impl Foo {
        fn read_data(&self) {
            // add code here
        }
        fn create_bar<'a>(&'a mut self) -> Bar<'a> {
            Bar {
                some_str: "test2",
                marker: PhantomData,
            }
        }
    }
    
    fn process(_arr: &mut [Bar]) {}
    
    fn main() {
        let mut foo = Foo { some_str: "test" };
        let mut array: [Bar; 1] = [foo.create_bar()];
        process(&mut array);
        foo.read_data();
    }
    

    使用 NLL,借用检查器变得更加先进和精确;它现在可以理解在调用process 之后您没有使用array,因此以新的方式使用foo 是安全的。

    【讨论】:

      猜你喜欢
      • 2018-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多