比超级特质更严格的关联类型限制的特质

5

我有一个简单的特性,它带有一个没有限制的关联类型。

trait Board {
    type Move;
    fn moves(&self) -> Vec<Self::Move>;
}

我希望您能将这个特质用作超特质。特别是,我希望我的新子特质对关联类型有更严格的限制。类似于这样的内容:
trait TextBoard: Board {
    type Move: fmt::Debug; // Trying to tighten bounds on associated type
    fn printMoves(&self) {
        println!("{:?}", self.moves());
    }
}

这个例子高度简化,但似乎展示了问题:编译器认为我正在尝试创建一个新的关联类型,但我只想让子trait需要更严格的约束条件。有没有办法实现这一点?


1
创建一个独立的函数printMoves,它接受一个&Board<Move = T>,其中T: fmt::Debug,这样做能解决你的问题吗?或者你坚持使用改进的trait? - Matthieu M.
1个回答

12

这是你所要求的:

trait TextBoard: Board
where
    Self::Move: Debug,
{
    // ...
}

所有对特征的限制都必须在"headline"中,不能在编写特征的正文中添加额外的限制。这个限制将防止你在<Foo as Board>::Move没有实现Debug时编写impl TextBoard for Fooplayground)。


也许这正是您想要的,但您真的需要防止为其他类型实现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());
    }
}

这个版本中,你依然不需要为那些 Self::Move: Debug 的类型编写一个 impl,但是你也不会被阻止为其他一些不满足条件的类型编写 impl。这更像是一种扩展而不是改进。


另一方面,几乎总是应该为每种类型实现 Debug,那么这个 trait 真的有用吗?也许你只想在 Board 上实现一个可选方法,当其满足 Move: Debug 时实现:

trait Board {
    type Move;

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

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

这就像原版本一样,但不需要添加新的 TextBoard 特质,所以它可能会减少您需要编写的明确边界数。许多标准库特质(例如Iterator)都定义了具有此类边界的可选方法。除了要求Move 必须Debug之外,缺点是它会使Board特质混乱不堪,因为其中包含打印代码,您可能不认为这真正意味着成为一个Board


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接