Как указать, что время жизни от impl должно быть таким же, как время жизни «я»? - PullRequest
0 голосов
/ 29 сентября 2018

Я начинаю с корня Fmt и рекурсивно спускаюсь (вдоль Vec<String>) в Fmt s, создаваемый вызовом get_subfmt.Когда вектор пуст, я вызываю метод (для краткости здесь не показан).Каждый предшествующий Fmt (и его BoxOrRef), естественно, имеет больший срок службы, обусловленный областью действия рекурсивной функции, чем следующий.Это кажется безопасным, но я очень плохо знаком с жизненным бизнесом, поэтому я мог ошибиться в своих рассуждениях где-то.

Рассмотрим следующий фрагмент упрощенного кода:

use std::borrow::Borrow;

pub trait Fmt {
    fn get_subfmt<'a>(&'a self, name: &str) -> Option<BoxOrRef<'a, dyn Fmt>>;
}

pub enum BoxOrRef<'a, T: ?Sized + 'a> {
    Boxed(Box<T>),
    Ref(&'a T)
}

impl<'b, T: Borrow<dyn Fmt + 'b>> Fmt for T {
    fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
        self.borrow().get_subfmt(name)
    }
}

Это не удаетсясо следующими ошибками:

error[E0308]: method not compatible with trait
  --> src/lib.rs:13:5
   |
13 |     fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected type `fn(&'a T, &str) -> std::option::Option<BoxOrRef<'a, Fmt + 'a>>`
              found type `fn(&'b T, &str) -> std::option::Option<BoxOrRef<'b, Fmt + 'b>>`
note: the lifetime 'a as defined on the method body at 13:5...
  --> src/lib.rs:13:5
   |
13 |     fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 12:1
  --> src/lib.rs:12:1
   |
12 | impl<'b, T: Borrow<dyn Fmt + 'b>> Fmt for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: method not compatible with trait
  --> src/lib.rs:13:5
   |
13 |     fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
   |
   = note: expected type `fn(&'a T, &str) -> std::option::Option<BoxOrRef<'a, Fmt + 'a>>`
              found type `fn(&'b T, &str) -> std::option::Option<BoxOrRef<'b, Fmt + 'b>>`
note: the lifetime 'b as defined on the impl at 12:1...
  --> src/lib.rs:12:1
   |
12 | impl<'b, T: Borrow<dyn Fmt + 'b>> Fmt for T {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the method body at 13:5
  --> src/lib.rs:13:5
   |
13 |     fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Кажется, что компилятор не может доказать, что 'a из определения get_subfmt совпадает с 'b из impl, скорее всегопотому что я не сказал, что это так.Как мне сообщить компилятору, что ссылка self должна длиться ровно 'b?Я не могу шлепнуть <'a: 'b> на get_subfmt в impl, так как это не соответствует сигнатуре метода.Я пытался ограничить T значением T: Borrow<dyn Fmt + 'b> + 'b, но это не помогает, ошибки остаются.

Я мог бы переместить 'a из метода к самому Fmt, но это нене кажется правильным, поэтому я хотел бы избежать этого, если есть способ.

1 Ответ

0 голосов
/ 30 сентября 2018

Это лучшее, что я мог придумать:

use std::borrow::Borrow;

pub trait Fmt<'b> {
    fn get_subfmt<'a>(&'a self, name: &str) -> Option<BoxOrRef<'a, dyn Fmt + 'a>>
    where
        'b: 'a;
}

pub enum BoxOrRef<'a, T: ?Sized + 'a> {
    Boxed(Box<T>),
    Ref(&'a T)
}

impl<'b, T: Borrow<dyn Fmt<'b> + 'b>> Fmt<'b> for T {
    fn get_subfmt<'a>(&'a self, name: &str) -> Option<BoxOrRef<'a, dyn Fmt + 'a>>
    where
        'b: 'a,
    {
        self.borrow().get_subfmt(name)
    }
}

Мы хотим, чтобы предел 'b: 'a ('b пережил 'a), а не 'a: 'b, потому что заимствованная ссылка не может пережитьего референт.

...