如何指定 impl 的生命周期应该与 'self' 的生命周期相同?

How to specify that a lifetime from an impl should be the same as the lifetime of 'self'?

我从根 Fmt 开始递归(沿着 Vec<String>)进入 get_subfmt 调用产生的 Fmt。当向量为空时,我调用一个方法(为简洁起见,此处未显示)。每个前面的 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>> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

编译器似乎无法证明 get_subfmt 定义中的 'aimpl 中的 'b 相同,很可能是因为我没有告诉它它是。如何与编译器沟通我希望 self 引用精确到最后 'b?我不能在 impl 中的 get_subfmt 上添加 <'a: 'b>,因为它与方法签名不匹配。我已经尝试将 T 限制为 T: Borrow<dyn Fmt + 'b> + 'b,但这没有帮助,错误仍然存​​在。

我可以将 'a 从方法移动到 Fmt 本身,但它看起来并不正确,所以如果有办法的话我想避免它。

这是我能想到的最好的:

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,因为借用的引用不能比它的引用长。