我想定义一个特征,该特征具有另一个特征,该特征具有自己的特征对象类型作为关联类型:
/// 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,以获取(大致)我正在尝试做的示例。
是否可以解决此问题,并让Bootstrapper
为Self
指定Output
(不是 printFuel($id)
)?
答案 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
,这要求Bootstrapper
是Make<Traits = BootstrapperTraits>
。
有关完整解决方案,请参见此Rust playground。