"How do I print a Vec?" — a question every Rust developer has asked
\n\nIf you've ever written in Rust and tried to simply print a vector to the screen, you've likely encountered this:
\n\nfn main() {\n let numbers = vec![1, 2, 3, 4, 5];\n println!("{}", numbers); // Error!\n}\n\nThe compiler greets you with a red message: `Vec<{integer}>` doesn't implement `std::fmt::Display`. Sound familiar? This question on Stack Overflow has gathered thousands of views, and for good reason. In Rust, there's no "magic" — the compiler requires you to specify how exactly you want to display the collection. And that's great, because it gives you full control.
In this article, we'll cover all the main ways to print a Vec in Rust: from quick debug output to creating beautiful formatting for the user. You'll learn which method to use when, and stop being afraid of compilation errors.
\n\nWhy doesn't Vec implement Display?
\n\nBefore jumping into the code, let's understand Rust's philosophy. The Display trait is intended for displaying data to the user — the way you want to see it in the interface. And Debug is for debugging and logs.
For a vector, it's impossible to guess which format you need:
\n- \n
- Print elements separated by commas? \n
- Each element on a new line? \n
- In square brackets, like an array? \n
- Or as a table? \n
That's why Rust developers decided not to impose a single format, but to leave the choice to the programmer. Let's look at what options we have.
\n\nMethod 1: Quick Debug Output (Debug)
\n\nThe simplest way is to use {:?} or {:#?} (pretty-print). For this, the element type of the vector must implement the Debug trait.
fn main() {\n let numbers = vec![1, 2, 3, 4, 5];\n println!("{:?}", numbers); // [1, 2, 3, 4, 5]\n println!("{:#?}", numbers); // Pretty output:\n // [\n // 1,\n // 2,\n // 3,\n // 4,\n // 5\n // ]\n}\n\nWhen to use: debugging, logging, quick checks. Usually not suitable for production — the format is inflexible.
\n\nImportant: if your type doesn't implement Debug, the compiler will tell you. For your own structs, you can add #[derive(Debug)]:
#[derive(Debug)]\nstruct Point {\n x: f64,\n y: f64,\n}\n\nfn main() {\n let points = vec![Point { x: 1.0, y: 2.0 }, Point { x: 3.0, y: 4.0 }];\n println!("{:?}", points);\n}\n\nMethod 2: Manual Iteration with an Iterator
\n\nThe most flexible way is to write your own loop. You get full control over the format.
\n\nfn main() {\n let words = vec!["hello", "world", "rust"];\n \n // Option 1: comma-separated\n for (i, word) in words.iter().enumerate() {\n if i > 0 {\n print!(", ");\n }\n print!("{}", word);\n }\n println!(); // hello, world, rust\n\n // Option 2: each on a new line\n for word in &words {\n println!("- {}", word);\n }\n // - hello\n // - world\n // - rust\n}\n\nThis approach gives maximum flexibility but requires more code. Great for when you need unique formatting.
\n\nMethod 3: Using an Iterator with collect and join
\n\nIf you simply need to join elements into a string, you can use join from the SliceConcatExt trait (available for slices):
fn main() {\n let words = vec!["hello", "world", "rust"];\n let joined = words.join(", ");\n println!("{}", joined); //