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.