【问题标题】:Rust `Vec` - cannot borrow `Vec` as immutable inside `impl` method (error[E0502])Rust `Vec` - 不能在`impl`方法中借用`Vec`作为不可变(错误[E0502])
【发布时间】:2020-07-09 10:09:42
【问题描述】:

关于 Rust 的error[E0502] 的问题有很多答案,但我无法真正理解一个特定的案例。我有一个struct,它的impl 方法是这样的:

struct Test {
  test_vec: Vec<i32>,
}

impl Test {
  // other methods...

  fn test(&mut self) -> i32 {
    self.test_vec.swap(0, self.test_vec.len() - 1);

    // other operations...
  }
}

试图编译立即导致错误:

错误[E0502]:不能将self.test_vec 借为不可变,因为它也借为可变

self.test_vec.swap(0, self.test_vec.len() - 1);
------------- ----    ^^^^^^^^^^^^^ immutable borrow occurs here
|             |
|             mutable borrow later used by call
mutable borrow occurs here

谁能解释一下为什么?看起来我并没有试图在那里借用self.test_vec,我正在传递len() 调用的usize 类型结果。另一方面:

fn test(&mut self) -> i32 {
  let last_index = self.test_vec.len() - 1;

  self.test_vec.swap(0, last_index);

  // other operations...
}

使用临时变量,它按预期工作,让我认为len() 调用以某种方式被评估它到达swap,因此被借用?我是不是因为语法糖而看不到东西?

【问题讨论】:

    标签: vector rust borrowing


    【解决方案1】:

    您必须以编译器的方式来考虑这一点。当你写:

    self.test_vec.swap(0, self.test_vec.len() - 1);
    

    编译器看到的:

    let temp1 = &mut self.test_vec;      // Mutable borrow of self.test_vec
    let temp2 = &self.test_vec;          // (ERROR!) Shared borrow of self.test_vec for use on getting the length
    let temp3 = Vec::len(temp2) - 1; 
    Vec::swap(temp1, 0, temp3);
    

    如您所见,您首先可变地借用self.test_vec,然后尝试获取长度,这是另一个借用。由于第一次借用是可变的并且仍然有效,所以第二次借用是非法的。

    当您使用临时变量时,您实际上是在重新排序借用,并且由于 self.test_vec.len() 在下一个可变借用之前终止借用,因此没有冲突。

    您可以争辩说编译器应该能够看到您的代码是正确的(如果以正确的方式解释),但编译器显然还不够聪明,无法做到这一点。

    【讨论】:

    • 感谢您的解释。但是,为什么在self.test_vec.len() - 1 借用实际上 期间会发生?我自然希望运算顺序首先计算向量的长度,然后将函数调用为Vec::swap(&amp;mut self.test_vec, 0, x - 1)
    • 这个问题与Vec::swap()基本无关。首先为保存&amp;mut self.test_vec 创建一个临时变量(我们看不到),然后为0 创建一个,然后为self.test_vec.len() - 1 创建一个。这可能不是 100% 准确,但如果您这样想,很明显当第三个临时变量生成时,第一个临时变量仍在范围内。我将编辑我的答案以显示这一点。
    • 这样就更清楚了。我通过传递对函数的可变引用进行了检查,编译器相当抱怨双重可变借用是非法的——这是可以理解的。感谢您花时间描述这种行为!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    相关资源
    最近更新 更多