Почему я не могу вызвать метод после уничтожения переменной, но я могу, если я получу доступ к полю напрямую? - PullRequest
0 голосов
/ 19 февраля 2019

Следующее не скомпилировано:

use std::any::Any;

pub trait CloneBox: Any {
    fn clone_box(&self) -> Box<dyn CloneBox>;
}

impl<T> CloneBox for T
where
    T: Any + Clone,
{
    fn clone_box(&self) -> Box<dyn CloneBox> {
        Box::new(self.clone())
    }
}

struct Foo(Box<dyn CloneBox>);

impl Clone for Foo {
    fn clone(&self) -> Self {
        let Foo(b) = self;
        Foo(b.clone_box())
    }
}

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

error[E0495]: cannot infer an appropriate lifetime for pattern due to conflicting requirements
  --> src/lib.rs:20:17
   |
20 |         let Foo(b) = self;
   |                 ^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 19:5...
  --> src/lib.rs:19:5
   |
19 | /     fn clone(&self) -> Self {
20 | |         let Foo(b) = self;
21 | |         Foo(b.clone_box())
22 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:20:17
   |
20 |         let Foo(b) = self;
   |                 ^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `&std::boxed::Box<dyn CloneBox>` will meet its required lifetime bounds
  --> src/lib.rs:21:15
   |
21 |         Foo(b.clone_box())
   |  

Однако, если изменить код в clone() с Foo(b.clone_box())на Foo(self.0.clone_box()) компилируется без проблем.Теоретически, доступ к полю должен быть таким же, как сопоставление с образцом, но почему сопоставление с образцом имеет проблемы с временем жизни?

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

1 Ответ

0 голосов
/ 19 февраля 2019

TL; DR: разыменовать значение перед вызовом метода:

Foo((*b).clone_box())

При let Foo(b) = self тип b равен &Box<(dyn CloneBox + 'static)>.Вызов метода фактически

Foo(<&Box<dyn CloneBox + 'static> as CloneBox>::clone_box(&b))

Это значение не может быть преобразовано в объект признака Box<dyn CloneBox + 'static> из-за локальной ссылки.Забавно, но я полагаю, что это было бы рекурсивно с использованием полной реализации, если бы компилятор позволял это.

При self.0.clone_box() вызов метода эффективен:

Foo(<dyn CloneBox as CloneBox>::clone_box(&**b)

Мы можем записать это как Foo((&**b).clone_box()), чтобы оно было явным, но поскольку промежуточных реализаций нет, Foo((*b).clone_box()) достаточно.

См. Также:

...