有没有办法让一个特征在它扩展的另一个特征中为关联类型指定自己?

Is there a way to have a trait specify itself for an associated type in another trait that it extends?

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

/// 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.

但是,我不能这样做,因为它会造成无限循环。在上面的示例中,我需要为 dyn Bootstrapper 指定 Output,它本身就是 (dyn Bootstrapper)。但是,我需要为 that dyn Bootstrapper 指定 Output,依此类推,例如Make<Output = dyn Bootstrapper<Output = dyn Bootstrapper<Output = dyn Bootstrapper<...>>>.

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

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.
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我也不能指定 Output = Self,因为那样会过度限制特征,因此 Bootstrapper 的给定实现只能 make() 本身。我想要一个 Bootstrapper 能够 make() 其他种类的 Bootstrapper。请参阅此 Rust playground 以了解(大致)我正在尝试做的事情的示例。

有没有办法解决这个问题,让Bootstrapper为[=12=指定Bootstrapper不是Self) ]?

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

/// 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 并将其传递给 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 指定为 Outputtype Traits 来绕过循环超特征依赖。然后 BootstrapperTraits 被指定为 Bootstrapper 的特定 Traits 实现。因此,任何实施 Bootstrapper 的人现在也必须实施 Make<Traits = BootstrapperTraits>,这要求 Outputdyn Bootstrapper.

请参阅此 Rust playground 以获得完整的解决方案。