为什么在trait中添加一个通用类型会影响trait对象和关联类型的寿命?

问题描述 投票:0回答:1

我有以下代码。

trait T<GT> {
    type AT;

    fn foo(&self);
}

struct AbstractT<GT, AT> {
    t: Box<dyn T<GT, AT = AT>>,
}

impl<GT, AT> T<GT> for AbstractT<GT, AT> {
    type AT = AT;

    fn foo(&self) {
        self.t.foo();
    }
}

fn boxed_abstract<GT, TT: T<GT> + 'static>(tt: TT) -> Box<dyn T<GT, AT = TT::AT>> {
    Box::new(AbstractT { t: Box::new(tt) })
}

playground

这引发了这些错误。

error[E0310]: the associated type `<TT as T<GT>>::AT` may not live long enough
  --> src/lib.rs:20:5
   |
20 |     Box::new(AbstractT { t: Box::new(tt) })
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = help: consider adding an explicit lifetime bound `<TT as T<GT>>::AT: 'static`...
note: ...so that the type `AbstractT<GT, <TT as T<GT>>::AT>` will meet its required lifetime bounds
  --> src/lib.rs:20:5
   |
20 |     Box::new(AbstractT { t: Box::new(tt) })
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0310]: the parameter type `GT` may not live long enough
  --> src/lib.rs:20:5
   |
19 | fn boxed_abstract<GT, TT: T<GT> + 'static>(tt: TT) -> Box<dyn T<GT, AT = TT::AT>> {
   |                   -- help: consider adding an explicit lifetime bound...: `GT: 'static`
20 |     Box::new(AbstractT { t: Box::new(tt) })
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
note: ...so that the type `AbstractT<GT, <TT as T<GT>>::AT>` will meet its required lifetime bounds
  --> src/lib.rs:20:5
   |
20 |     Box::new(AbstractT { t: Box::new(tt) })
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如果我删除 GT 从任何地方来的,它都能很好地编译,但如果有了 GT 它以一堆寿命错误失败。看来,存在 GT 不应影响任何一方的寿命。dyn TT::AT (因为在它们中没有使用),但显然是这样的。同样的,一生的 dyn T 不应依赖寿命 GTAT 但显然是这样的。

是我遗漏了什么,还是这是个终身推理的问题?

rust traits lifetime associated-types
1个回答
1
投票

你可能遗漏了什么。Rust会自动推断特质对象的寿命边界,在盒状特质对象的情况下,自动推断的寿命边界是指 'static. 例如,当Rust编译器查看你的代码时,它看到的就是这个。

trait T<GT> {
    type AT;

    fn foo(&self);
}

struct AbstractT<GT, AT> {
    // notice the added "+ 'static" below
    t: Box<dyn T<GT, AT = AT> + 'static>,
}

impl<GT, AT> T<GT> for AbstractT<GT, AT> {
    type AT = AT;

    fn foo(&self) {
        self.t.foo();
    }
}

// notice the added "+ 'static" in the return type
fn boxed_abstract<GT, TT: T<GT> + 'static>(tt: TT) -> Box<dyn T<GT, AT = TT::AT> + 'static> {
    Box::new(AbstractT { t: Box::new(tt) })
}

为了使它能被编译,我们只需要添加更多的显式的 'static 你所有的通用类型的界限,像这样。

trait T<GT> {
    type AT;

    fn foo(&self);
}

struct AbstractT<GT, AT> {
    t: Box<dyn T<GT, AT = AT>>,
}

impl<GT, AT> T<GT> for AbstractT<GT, AT> {
    type AT = AT;

    fn foo(&self) {
        self.t.foo();
    }
}

fn boxed_abstract<GT, TT>(tt: TT) -> Box<dyn T<GT, AT = TT::AT>>
    where TT: T<GT> + 'static, GT: 'static
{
    Box::new(AbstractT { t: Box::new(tt) })
}

playground

我们之所以需要这些 'static bounds很简单:一个容器类型只能由 'static 如果它里面的所有类型都被称为 'static 以此类推递归。

进一步的阅读。

更新

如果你不喜欢 'static 你可以提出 AbstractT 通过给它的类型添加一个显式的寿命注解来实现对寿命的通用,就像这样。

trait T<GT> {
    type AT;

    fn foo(&self);
}

struct AbstractT<'a, GT, AT> {
    t: Box<dyn T<GT, AT = AT> + 'a>,
}

impl<'a, GT, AT> T<GT> for AbstractT<'a, GT, AT> {
    type AT = AT;

    fn foo(&self) {
        self.t.foo();
    }
}

fn boxed_abstract<'a, GT, TT>(tt: TT) -> Box<dyn T<GT, AT = TT::AT> + 'a>
    where TT: T<GT> + 'a, GT: 'a
{
    Box::new(AbstractT { t: Box::new(tt) })
}

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.