6

Learning the language it's been surprising to me I cannot print an instance of Vec:

fn main() {
    let v1 = vec![1, 2, 3];
    println!("{}", v1);
}
error[E0277]: `std::vec::Vec<{integer}>` doesn't implement `std::fmt::Display`
 --> src/main.rs:3:20
  |
3 |     println!("{}", v1);
  |                    ^^ `std::vec::Vec<{integer}>` cannot be formatted with the default formatter
  |
  = help: the trait `std::fmt::Display` is not implemented for `std::vec::Vec<{integer}>`
  = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
  = note: required by `std::fmt::Display::fmt`

I can understand that and I'm aware of using {:?} debug placeholder as described here. Unfortunately, I don't yet understand the answer that tells why I cannot do that. It would be pretty trivial task for either C# or Haskell, wouldn't it? I'd implement the Display trait for Vec<T> for any T that is serializable (or convertible to String). Can I have a different explanation on why I can't do that? Is it a limitation of the type system?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
UserControl
  • 14,766
  • 20
  • 100
  • 187
  • 2
    Have you seen http://stackoverflow.com/questions/30633177/implement-fmtdisplay-for-vect ? That question also asks why you can't implement `Display` for `Vec` – oli_obk Nov 17 '15 at 14:20
  • Thanks! Still, I don't get it. Why do I need an extra thing like `struct` to implement a trait? – UserControl Nov 17 '15 at 14:32
  • 1
    Because if you could, someone else also could, and then you'd have two implementations and the compiler can never know which one to call – oli_obk Nov 17 '15 at 14:34
  • @ker, why would that be a problem if there is no conflicting trait implementation in the current crait? – UserControl Nov 17 '15 at 15:57
  • 1
    because your crate might be a library. And then someone might use your crate and another crate that also has an impl and end up with two impls. – oli_obk Nov 17 '15 at 16:45

1 Answers1

19

First, you can't implement a foreign trait for a foreign type, that's what the question and answer the link to which ker has provided are about.

In principle, nothing prevents implementing Display for Vec in a module where either of them is defined (most likely in collections::vec). However, this is intentionally not done. As is explained in this and this RFCs, the Display trait is intended to produce strings which should be displayed to the user. However, there is no natural way to produce such a string from a vector. Do you want comma-separated items or tab-separated ones? Should they be wrapped in brackets or curly braces or nothing? Maybe you want to print each element on its separate line? There is no one single way.

The simplest way to work around this would be to use a newtype wrapper. For example:

use std::fmt;

struct SliceDisplay<'a, T: 'a>(&'a [T]);

impl<'a, T: fmt::Display + 'a> fmt::Display for SliceDisplay<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut first = true;
        for item in self.0 {
            if !first {
                write!(f, ", {}", item)?;
            } else {
                write!(f, "{}", item)?;
            }
            first = false;
        }
        Ok(())
    }
}

fn main() {
    let items = vec![1, 2, 3, 4];
    println!("{}", SliceDisplay(&items));
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296