Traits with stricter associated type bounds than supertrait

こ雲淡風輕ζ 提交于 2020-01-24 18:58:22

问题


I have a simple trait with an associated type with no bounds.

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

I also want to use this trait as a supertrait. In particular, I want my new subtrait to have stricter bounds on the associated type. Something like this:

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

The example is highly simplified, but seems to show the problem: The compiler thinks I'm trying to create a new associated type, but I just want the subtrait to require tighter bounds. Is there any way to achieve this?


回答1:


Here's what you asked for:

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

All the bounds on a trait have to be in the "headline"; you can't impose additional restrictions once you start writing the body of the trait. This bound will prevent you from writing impl TextBoard for Foo when <Foo as Board>::Move does not implement Debug (playground).


Maybe that is what you want, but do you really need to prevent implementing TextBoard for other types? For some type there could be another way to write print_moves that makes more sense, and the Debug requirement is just noise. In that case you probably want to skip the where clause and move the body of print_moves to a blanket 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());
    }
}

With this version, you still don't need to write an impl for types where Self::Move: Debug, but you're not prevented from writing an impl for other types where that doesn't hold. It's more of an extension than a refinement.


On the other hand, you should pretty much always implement Debug for every type, so is it really useful to have that trait? Maybe what you want is just an optional method on Board that's implemented when Move: Debug:

trait Board {
    type Move;

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

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

This is like the original version, but doesn't require the addition of a new TextBoard trait, so it will probably cut down on the number of explicit bounds you have to write. Many of the standard library traits such as Iterator have optional methods defined with bounds like this. The downside, besides the requirement that Move must be Debug, is that it clutters the Board trait with printing code, which you might not consider really part of what it means to be a Board.



来源:https://stackoverflow.com/questions/47018493/traits-with-stricter-associated-type-bounds-than-supertrait

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!