有没有一种方法可以让特征为扩展的另一个特征指定自己的关联类型?

时间:2019-10-21 14:36:36

标签: rust traits associated-types

我想定义一个特征,该特征具有另一个特征,该特征具有自己的特征对象类型作为关联类型:

/// A trait for making things.
trait Make {
    type Output: ?Sized;
    fn make(self: Box<Self>) -> Box<Self::Output>;
}

/// A special case of Make, which makes things that impl the same trait.
trait Bootstrapper: Make<Output = dyn Bootstrapper> {} // Will NOT compile.

但是,我不能这样做,因为它会产生无限循环。在上面的示例中,我需要为Output指定dyn Bootstrapper,而dyn Bootstrapper本身就是(Output)。但是然后,我需要为那个 dyn Bootstrapper指定Make<Output = dyn Bootstrapper<Output = dyn Bootstrapper<Output = dyn Bootstrapper<...>>>,依此类推,例如error[E0391]: cycle detected when computing the supertraits of `Bootstrapper` --> src/lib.rs:8:1 | 8 | trait Bootstrapper: Make<Output = dyn Bootstrapper> {} // Will NOT compile. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: ...which again requires computing the supertraits of `Bootstrapper`, completing the cycle note: cycle used when collecting item types in top-level module --> src/lib.rs:8:1 | 8 | trait Bootstrapper: Make<Output = dyn Bootstrapper> {} // Will NOT compile. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Rust编译器似乎同意这行不通:

Output = Self

我也不能指定Bootstrapper,因为那样会过分限制特征,因此make()的给定实现只能Bootstrapper本身更多。我希望make()能够Bootstrapper其他类型的Bootstrapper。请参阅此Rust playground,以获取(大致)我正在尝试做的示例。

是否可以解决此问题,并让BootstrapperSelf指定Output不是 printFuel($id))?

1 个答案:

答案 0 :(得分:0)

我最终得到的解决方案是:

/// A meta-`trait` that defines the associated types for a subset of `Make`.
trait Traits {
    type Output : ?Sized;
}

/// A `trait` for making things. Takes in a set of `Traits` that define the
/// output for the `make()` function.
trait Make {
    type Traits : Traits;
    fn make(self : Box<Self>) -> Box<<Self::Traits as Traits>::Output>;
}

通过将关联的type分离为单独的Traits元接口,我能够为新的具体类型实现Traits并将其传递给{{1} }:

Make

具体类型(/// `Traits` implementation for `Bootstrapper`, which constrains the `Make` /// implementation for `Bootstrapper` to outputting a `Box<Bootstrapper>`. struct BootstrapperTraits; impl Traits for BootstrapperTraits { // NOTE: Specifying Self here gets around the circular dependency. type Output = dyn Bootstrapper<Traits = Self>; } /// A special case of Make that makes the same *kind* of thing as itself, but /// not *necessarily* `Self`. trait Bootstrapper : Make<Traits = BootstrapperTraits> { fn is_best(&self) -> bool; } )可以通过将BootstrapperTraits指定为Self的{​​{1}}来解决循环超性依赖。然后,将type Traits指定为Output的特定BootstrapperTraits实现。因此,实现Traits的任何人现在也必须实现Bootstrapper,这要求BootstrapperMake<Traits = BootstrapperTraits>

有关完整解决方案,请参见此Rust playground