Почему происходит заимствование перемещенного значения при вызове метода, который принимает себя по значению с аргументом, который также вызывает метод? - PullRequest
4 голосов
/ 12 марта 2019

Я столкнулся с проблемой, которая вынуждает меня разделить хороший пользовательский блок на {} блок с промежуточным let.Причина этого мне совершенно не ясна.Мне удалось выделить проблему в этом минимальном примере:

struct AB {
    a: u8,
    b: u8,
}

impl AB {
    fn foo(&self) -> String {
        String::from("foo")
    }
    fn bar(self, x: String) -> String {
        format!("{} - {} - {}!", x, self.a, self.b)
    }
}

fn main() {
    let x = AB { a: 3, b: 5 };
    let result = x.bar(x.foo());
    println!("{}", result);
}

У меня сложилось впечатление, что аргументы функции bar будут оцениваться до вызова bar.foo заимствует x во время его выполнения, но когда он возвращает String, заем заканчивается, так как String не является эталоном, имеющим срок службы x.Когда вызывается bar, заимствование foo должно быть закончено.

Однако компилятор не согласен:

error[E0382]: borrow of moved value: `x`
  --> src/main.rs:17:24
   |
17 |     let result = x.bar(x.foo());
   |                  -     ^ value borrowed here after move
   |                  |
   |                  value moved here
   |
   = note: move occurs because `x` has type `AB`, which does not implement the `Copy` trait

Я не согласен с тем фактом, что barдействительно движется x.Моя проблема с утверждением, что foo заимствует x после перемещения.

Простое (но безобразное) исправление:

struct AB {
    a: u8,
    b: u8,
}

impl AB {
    fn foo(&self) -> String {
        String::from("foo")
    }
    fn bar(self, x: String) -> String {
        format!("{} - {} - {}!", x, self.a, self.b)
    }
}

fn main() {
    let x = AB { a: 3, b: 5 };
    let y = x.foo();
    let result = x.bar(y);
    println!("{}", result);
}

разделениеприсваивание x.foo() промежуточной переменной y компилируется нормально, подтверждая мои ожидания того, что заем действительно закончится после возврата foo, но почему это работает?Что-то я не понимаю в порядке оценки?Почему я не могу избавиться от промежуточного let y?

1 Ответ

4 голосов
/ 12 марта 2019

Порядок оценки для заимствований слева направо.

Это означает, что предмет вызова bar, упоминание о x "исключения", рассматривается до упоминания о заимствовании x в вызове foo, и, следовательно, Компилятор считает, что переменная была перемещена из.

Для аналогичного случая, когда внешнее упоминание является изменчивым заимствованием, RFC 2025 было принято в качестве решения, но еще не реализовано. К сожалению, этот RFC, по-видимому, не охватывает ваш случай, когда внешнее использование является ходом.

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