Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't Vec<T> implement the Display trait?

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?

like image 672
UserControl Avatar asked Dec 06 '22 19:12

UserControl


1 Answers

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));
}
like image 186
Vladimir Matveev Avatar answered Jan 13 '23 00:01

Vladimir Matveev