具有比supertrait更严格的相关类型边界的特征

Mor*_*hne 2 rust

我有一个简单的特征,其关联类型没有边界.

trait Board {
    type Move;
    fn moves(&self) -> Vec<Self::Move>;
}
Run Code Online (Sandbox Code Playgroud)

我也想把这个特性用作超级特征.特别是,我希望我的新子特征对相关类型有更严格的界限.像这样的东西:

trait TextBoard: Board {
    type Move: fmt::Debug; // Trying to tighten bounds on associated type
    fn printMoves(&self) {
        println!("{:?}", self.moves());
    }
}
Run Code Online (Sandbox Code Playgroud)

这个例子是高度简化的,但似乎显示了问题:编译器认为我正在尝试创建一个新的关联类型,但我只是想让子文章需要更严格的边界.有没有办法实现这个目标?

tre*_*tcl 8

这是你要求的:

trait TextBoard: Board
where
    Self::Move: Debug,
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

特质的所有界限都必须在"标题"中; 一旦开始编写特征的主体,就不能施加额外的限制.impl TextBoard for Foo<Foo as Board>::Move没有实现Debug(playground)时,此绑定将阻止您写入.


也许这就是你想要的,但你真的需要阻止TextBoard其他类型的实现吗?对于某些类型,可能有另一种写法print_moves更有意义,而Debug要求只是噪音.在这种情况下,您可能希望跳过该where子句并将主体移动print_moves毯子impl:

trait TextBoard {
    fn print_moves(&self);
}

impl<B: Board> TextBoard for B
where
    B::Move: Debug, // or <Self as Board>::Move: Debug
{
    fn print_moves(&self) {
        println!("{:?}", self.moves());
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此版本,您仍然不需要impl为其中的类型编写Self::Move: Debug,但是您不会阻止编写impl其他不适用的类型.它更像是一个扩展,而不是一个改进.


另一方面,你应该总是Debug为每种类型实现,所以具有这种特性真的很有用吗?也许你想要的只是一个可选的方法Board,在以下情况下实现Move: Debug:

trait Board {
    type Move;

    fn moves(&self) -> Vec<Self::Move>;

    fn print_moves(&self)
    where
        Self::Move: Debug,
    {
        println!("{:?}", self.moves());
    }
}
Run Code Online (Sandbox Code Playgroud)

这与原始版本类似,但不需要添加新TextBoard特征,因此它可能会减少您必须编写的显式边界的数量.许多标准库特性,例如使用这样的Iterator边界定义的可选方法.不足之处,除此之外的要求Move 必须Debug,是,它杂波的Board特性与印刷代码,你可能不考虑真正的这是什么意思是一个部分Board.