Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Rust why does an iterator of `ToString` items requires them to be `Display` also

The following code:

enum MyEnum {
    A,
    B,
}

impl ToString for MyEnum {
    fn to_string(&self) -> String {
        match *self {
            Self::A => format!("A"),
            Self::B => format!("B"),
        }
    }
}

pub fn foo<I: ToString>(item: I) {
    println!("item: {}", item.to_string());
}

pub fn bar<I: ToString>(iter: impl Iterator<Item = I>) {
    iter.for_each(|item| println!("item: {}", item.to_string()))
}

fn main() {
    foo(MyEnum::A);
    bar([MyEnum::A, MyEnum::B].iter());
}

Produces the following compilation error:

error[E0277]: `MyEnum` doesn't implement `std::fmt::Display`
  --> src\bin\main6.rs:25:2
   |
25 |     bar([MyEnum::A, MyEnum::B].iter());
   |     ^^^ `MyEnum` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `MyEnum`
   = 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 `&MyEnum`
   = note: required because of the requirements on the impl of `ToString` for `&MyEnum`
note: required by a bound in `bar`
  --> src\bin\main6.rs:19:15
   |
19 | pub fn bar<I: ToString>(iter: impl Iterator<Item = I>) {
   |               ^^^^^^^^ required by this bound in `bar`

For more information about this error, try `rustc --explain E0277`.

bar accepts iterators whose items implement ToString. MyEnum implements ToString, so [MyEnum::A, MyEnum::B].iter() is in fact an iterator of items that implement ToString.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

foo and bar are very similar, in both the generic type I is replaced with MyEnum, so why is the trait bound Display required in bar but not in foo?

>Solution :

[MyEnum::A, MyEnum::B].iter() creates an iterator whose item is &MyEnum. &MyEnum does not implement Display, only MyEnum does. This works:

enum MyEnum {
    A,
    B,
}

impl ToString for MyEnum {
    fn to_string(&self) -> String {
        match *self {
            Self::A => format!("A"),
            Self::B => format!("B"),
        }
    }
}

pub fn foo<I: ToString>(item: I) {
    println!("item: {}", item.to_string());
}

pub fn bar<I: ToString>(iter: impl Iterator<Item = I>) {
    iter.for_each(|item| println!("item: {}", item.to_string()))
}

fn main() {
    foo(MyEnum::A);
    bar([MyEnum::A, MyEnum::B].into_iter());
}

Playground

And if you want to accept any &I such that I: Display:

pub fn bar<'a, I: 'a>(iter: impl Iterator<Item = &'a I>) where I: ToString {
    iter.for_each(|item| println!("item: {}", item.to_string()))
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading