Мутабельный заем в петле - PullRequest
0 голосов
/ 01 мая 2018

У меня есть следующий код:

struct Baz {
    x: usize,
    y: usize,
}

struct Bar {
    baz: Baz,
}

impl Bar {
    fn get_baz_mut(&mut self) -> &mut Baz {
        &mut self.baz
    }
}

struct Foo {
    bar: Bar,
}

impl Foo {
    fn foo(&mut self) -> Option<&mut Baz> {
        for i in 0..4 {
            let baz = self.bar.get_baz_mut();
            if baz.x == 0 {
                return Some(baz);
            }
        }
        None
    }
}

Rust Playground

Не удается скомпилировать с:

error[E0499]: cannot borrow `self.bar` as mutable more than once at a time
  --> src/main.rs:23:23
   |
23 |             let baz = self.bar.get_baz_mut();
   |                       ^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
29 |     }
   |     - mutable borrow ends here

Однако, если я возвращаю Some(baz.x) из Foo::foo (и меняю тип возвращаемого значения на Option<usize>), код компилируется. Это заставляет меня поверить, что проблема не в цикле, хотя компилятор, кажется, указывает на это. Более конкретно, я считаю, что локальная изменяемая ссылка baz выйдет из области видимости на следующей итерации цикла, что приведет к тому, что это станет проблемой. В чем проблема срока службы вышеуказанного кода?

Следующие вопросы похожи:

Однако они имеют дело с явно объявленными временами жизни (и именно эти явные времена жизни являются частью ответа). Мой код пропускает эти времена жизни, поэтому удаление их не является решением.

1 Ответ

0 голосов
/ 01 мая 2018

Не работает, потому что возврат заимствованного значения продлевает заем до конца функции.

См. здесь для некоторых полезных деталей.

Работает с нелексическими временами жизни с 1.27 ночной версией:

#![feature(nll)]

struct Baz {
    x: usize,
    y: usize,
}

// ...

Нелексические времена жизни RFC объясняет фактическую работу времен жизни:

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

rustc nightly 1.28

Как указывает @ pnkfelix , реализация нелексических времен жизни, начиная с ночной версии 1.28, больше не компилирует вышеуказанный код.

Однако существует долгосрочный план для (более) включения более мощного анализа NLL .

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