Несколько жизней и перемещение: здесь происходит присвоение заимствованному `x` - PullRequest
0 голосов
/ 02 июня 2018

У меня есть структура с функцией next() (аналогично итераторам, но не итератору).Этот метод возвращает следующее состояние после модификации (сохранение исходного состояния).Итак: fn next(&A) -> A.

Я начал с простой структуры, где мне не требовалось время жизни (структура A в примере), и я расширил ее, добавив ссылку на новую структуру (структура B).

Проблема в том, что теперь мне нужно указать время жизни для моей структуры, и по какой-то причине мой метод next() больше не работает.

Я подозреваю, что время жизни новой структурыкаждая итерация ограничена областью, в которой она создана, и я не могу переместить ее за пределы этой области.

Можно ли сохранить поведение моего next() метода?

Попробуйте здесь

#[derive(Clone)]
struct A(u32);
#[derive(Clone)]
struct B<'a>(u32, &'a u32);

impl A {
    fn next(&self) -> A {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

impl<'a> B<'a> {
    fn next(&self) -> B {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

fn main() {
    let mut a = A(0);
    for _ in 0..5 {
        a = a.next();
    }

    let x = 0;
    let mut b = B(0, &x);
    for _ in 0..5 {
        b = b.next();
    }
}

Ошибка:

error[E0506]: cannot assign to `b` because it is borrowed
  --> src/main.rs:31:9
   |
31 |         b = b.next();
   |         ^^^^-^^^^^^^
   |         |   |
   |         |   borrow of `b` occurs here
   |         assignment to borrowed `b` occurs here

1 Ответ

0 голосов
/ 02 июня 2018

Проблема здесь:

impl<'a> B<'a> {
    fn next(&self) -> B {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

Вы не указали время жизни для B, тип возврата next.Из-за правил жизненного правила Rust компилятор делает вывод, что вы предполагали следующее:

impl<'a> B<'a> {
    fn next<'c>(&'c self) -> B<'c> {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

Что означает, что возвращаемое значение может не пережить self.Или, другими словами, self должен жить дольше, чем B, который возвращается.Учитывая тело функции, это совершенно ненужное требование , потому что эти ссылки независимы друг от друга.И здесь возникает проблема:

for _ in 0..5 {
    b = b.next();
}

Вы перезаписываете значение, которое, по мнению заемщика, все еще заимствовано при вызове next().Внутри next мы знаем, что таких отношений нет - аннотации времени жизни не отражают ограничений того, что вы на самом деле делаете.

Так каковы здесь границы времени жизни?

  1. Время жизни ссылок на B не связано - каждый может существовать без другого.Таким образом, чтобы обеспечить максимальную гибкость для вызывающей стороны, время жизни B должно отличаться от времени жизни ссылки на self в next.

  2. Однако каждыйB, созданный с помощью next(), содержит ссылку на того же u32, что и self.Таким образом, время жизни параметр , которое вы даете каждому B, должно быть одинаковым.

Используя явно именованные времена жизни, это результат объединения обеих этих вещей:

impl<'a> B<'a> {
    fn next<'c>(&'c self) -> B<'a> {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}

Обратите внимание, что - хотя ссылка - self здесь имеет время жизни 'c - тип self равен B<'a>, где 'a равенвремя жизни &u32 внутри.Точно так же, как возвращаемое значение.

Но на самом деле, 'c может быть исключено.Так что это действительно так же, как это:

impl<'a> B<'a> {
    fn next(&self) -> B<'a> {
        let mut new = self.clone();
        new.0 = new.0 + 1;
        new
    }
}
...