Как вернуть изменяемую ссылку на Необязательный штучный атрибут, хранящийся в элементе struct - PullRequest
2 голосов
/ 26 апреля 2019

Моя цель - вернуть изменяемую ссылку на объект черты, который хранится в коробке.

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

Попытка использовать тот же подход может привести к пожизненной проблеме.

Пример кода:

trait Baz {}

#[derive(Debug)]
struct Foo;

impl Baz for Foo {}

struct Bar {
    data: Option<Box<Baz>>,
}

enum BarErr {
    Nope,
}

impl Bar {
    fn borrow_mut(&mut self) -> Option<&mut Baz> {
        self.data.as_mut().map(|x| &mut **x)
    }
}

Ссылка на игровую площадку.

Сообщение об ошибке:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/lib.rs:20:9
   |
20 |         self.data.as_mut().map(|x| &mut **x)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected type `std::option::Option<&mut dyn Baz>`
              found type `std::option::Option<&mut (dyn Baz + 'static)>`
note: the anonymous lifetime #1 defined on the method body at 19:5...
  --> src/lib.rs:19:5
   |
19 | /     fn borrow_mut(&mut self) -> Option<&mut Baz> {
20 | |         self.data.as_mut().map(|x| &mut **x)
21 | |     }
   | |_____^
   = note: ...does not necessarily outlive the static lifetime

Я действительно не вижу, где продлится жизнь.

Также попытка заменить &mut **x на as_mut не помогает.

Ответы [ 2 ]

3 голосов
/ 26 апреля 2019

Это произошло из-за причуды в компиляторе.Давайте расширим время жизни в borrow_mut:

fn borrow_mut<'a>(&'a mut self) -> Option<&'a mut dyn Baz> {

Выражение

self.data.as_mut().map(|x| &mut **x)

было выведено, чтобы иметь тип Option<&mut dyn (Baz + 'static)>, в то время как функция ожидала вывода Option<&'a mut dyn (Baz + 'a)>.Это тонкое различие в ограничениях времени жизни, применяемых к объекту признака, не может быть разрешено простым принуждением, потому что изменяемые ссылки инвариантны относительно времени жизни объекта признака.

Что мы можем сделать, это либо согласиться на вывод изменяемой ссылки на dyn Baz + 'static:

fn borrow_mut<'a>(&'a mut self) -> Option<&'a mut (dyn Baz + 'static)> {
   self.data.as_mut().map(|x| x.as_mut())
}

Или скажите компилятору разрешить выражение в Option<&'a mut (dyn Baz + 'a)> другими способами, например, с помощью оператора match, оператора ? или оператора приведения.

impl Bar {
    fn borrow_mut(&mut self) -> Option<&mut dyn Baz> {
        self.data.as_mut().map(|x| &mut **x as &mut dyn Baz)
    }
}

См. Также: Ковариация типа Box в Rust

0 голосов
/ 26 апреля 2019

Кажется, использование синтаксиса деструктурирования решает эту проблему: Следующий код прекрасно компилируется:

fn borrow_mut(&mut self) -> Option<&mut Baz> {
    match &mut self.data {
        Some(e) => Some(e.as_mut()),
        None => None,
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...