Description
Consider this example (playground):
use std::fmt::{self, Display, Formatter};
// This struct provides a `Display` implementation that iterates over
// &collection, writing each element in sequence.
pub struct Concat<C> {
collection: C,
}
impl<C> Display for Concat<C>
where for <'a> &'a C: IntoIterator,
for <'a> <&'a C as IntoIterator>::Item: Display,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.collection.into_iter().try_for_each(move |element| {
element.fmt(f)
})
}
}
fn main() {
let collection = vec![1u32, 2, 3, 4, 5, 6];
let concat = Concat { collection };
println!("{}", concat);
}
We define a struct, Concat
, that provides a Display
implementation by immutably iterating over collection
and writing each element to f
in sequence. This trait implementation depends on the following trait bounds:
for<'a> &'a C: IntoIterator, // immutable iteration
for<'a> <&'a C as IntoIterator>::Item: Display // Items are displayable
However, the latter trait bound appears to not be binding correctly, as the example code fails to compile with the following error:
error[E0277]: `<&'a std::vec::Vec<u32> as std::iter::IntoIterator>::Item` doesn't implement `std::fmt::Display`
--> src/main.rs:23:20
|
23 | println!("{}", concat);
| ^^^^^^ `<&'a std::vec::Vec<u32> as std::iter::IntoIterator>::Item` cannot be formatted with the default formatter
|
= help: the trait `for<'a> std::fmt::Display` is not implemented for `<&'a std::vec::Vec<u32> as std::iter::IntoIterator>::Item`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required because of the requirements on the impl of `std::fmt::Display` for `Concat<std::vec::Vec<u32>>`
= note: required by `std::fmt::Display::fmt`
It's worth noting that the code does compile if you don't include the usage in main
. I've tried a lot of variations on this code, but the issue seems to boil down to the fact that Rust seems to consider for<'a> Display
different than display.
I posted this issue on stackoverflow, and got a response with the following workaround:
mod private {
use std::fmt;
pub trait Display<'a>: fmt::Display {}
impl<'a, T> Display<'a> for T where T: fmt::Display {}
}
impl<C> fmt::Display for Concat<C>
where
for<'a> &'a Container: IntoIterator,
for<'a> <&'a Container as IntoIterator>::Item: private::Display<'a>,
...
In summary, there appears to be an issue with binding an associated type to a trait in an HRTB context.