Rust `Vec` - невозможно заимствовать` Vec` как неизменяемый внутри метода `impl` (ошибка [E0502]) - PullRequest
2 голосов
/ 09 июля 2020

Есть много ответов на вопросы о error[E0502] Rust, но я не могу понять один конкретный случай. У меня есть 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...
  }
}

Попытка скомпилировать, которая немедленно приводит к ошибке:

error [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, я передаю результат типа usize вызова len(). С другой стороны:

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

  self.test_vec.swap(0, last_index);

  // other operations...
}

Используя временную переменную, она работает, как ожидалось, заставляет меня думать, что вызов len() каким-то образом оценивается после он достигает swap, и таким образом будучи заимствованным? Я что-то не вижу из-за синтаксического сахара?

1 Ответ

1 голос
/ 09 июля 2020

Вы должны думать об этом так, как это делает компилятор. Когда вы пишете:

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() завершает заимствование перед следующим изменяемым заимствованием, конфликтов нет.

Вы можете утверждать, что компилятор должен быть в состоянии видеть, что ваш код может быть правильным (если он интерпретируется правильно), но компилятор явно еще недостаточно умен, чтобы сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...