是否有一种特征可以为其自身所扩展的另一个特征中的关联类型指定自身?

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

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

/// 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。但是然后,我需要为that Output指定dyn Bootstrapper,依此类推,例如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指定Bootstrappernot Self)为Output

rust traits associated-types
1个回答
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并将其传递给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指定为type TraitsOutput来避开圆形特征。然后,将BootstrapperTraits指定为Traits的特定Bootstrapper实现。因此,实现Bootstrapper的任何人现在还必须实现Make<Traits = BootstrapperTraits>,这要求Outputdyn Bootstrapper

请参阅此Rust playground了解完整的解决方案。

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