如何指定一个impl的生存期应该与“ self”的生存期相同?

时间:2018-09-29 20:53:31

标签: rust lifetime

我从根Fmt开始,然后递归下降(沿着Vec<String>)到Fmt调用产生的get_subfmt s中。当向量为空时,我调用一个方法(为简便起见,此处未显示)。与递归函数的作用域相比,前一个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>的{​​{1}}上打get_subfmt,因为这与方法签名不匹配。我尝试将impl约束为T,但这无济于事,错误仍然存​​在。

我可以将T: Borrow<dyn Fmt + 'b> + 'b从方法移到'a本身,但这似乎并不正确,因此,如果可以的话,我想避免这样做。

1 个答案:

答案 0 :(得分:1)

这是我能想到的最好的方法

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,因为借用的引用不能超过其引用的寿命。