Question
I tried to print a Rust vector using println!("{}", v2), but the compiler reports that Vec<T> does not implement std::fmt::Display.
fn main() {
let v2 = vec![1; 10];
println!("{}", v2);
}
The compiler error says:
error[E0277]: `std::vec::Vec<{integer}>` doesn't implement `std::fmt::Display`
--> src/main.rs:3:20
|
3 | println!("{}", v2);
| ^^ `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`
Why does this happen, and is Display implemented for Vec<T>? If not, how should a vector be printed in Rust?
Short Answer
By the end of this page, you will understand why Vec<T> cannot be printed with {} in Rust, when to use {:?} instead, and how Display differs from Debug. You will also learn practical ways to print vectors, including pretty-printing and creating custom output when you want a human-friendly format.
Concept
Rust has two common formatting traits for printing values:
Display→ for user-facing, clean output with{}Debug→ for developer-facing output with{:?}
A Vec<T> implements Debug, but not Display.
That means this works:
let v = vec![1, 2, 3];
println!("{:?}", v);
But this does not:
let v = vec![1, 2, 3];
println!("{}", v); // error
Why Vec<T> does not implement Display
Display is meant to produce a single, clear, human-readable representation. For a vector, there is no one obvious display format:
- Should it print as
[1, 2, 3]? - Or
1, 2, 3? - Or one item per line?
- Should strings be quoted?
- Should nested vectors be indented?
Because different programs want different output styles, Rust does not choose one default Display format for Vec<T>.
Why Debug is implemented
Debug exists specifically to help developers inspect values while coding, testing, or debugging. A vector has a natural debug representation, so Rust provides one.
Example:
let v = vec![1, 2, 3];
println!("{:?}", v); // [1, 2, 3]
println!("{:#?}", v); // pretty printed
Can you implement Display for Vec<T> yourself?
Not directly.
Because both the trait (Display) and the type (Vec<T>) are defined outside your crate, Rust's orphan rules prevent this implementation:
// Not allowed
impl<T> std::fmt::Display for Vec<T> {
// ...
}
If you want custom display formatting, the usual solution is to create your own wrapper type and implement Display for that wrapper.
Mental Model
Think of Display and Debug as two different labels on a printer:
Display= show this nicely to a userDebug= show this clearly to a programmer
A Vec<T> is like a box full of items. If someone says, "print the box nicely," Rust asks: what does nicely mean?
- As a comma-separated list?
- As JSON-like text?
- As a vertical list?
There is no single best answer, so Rust refuses to guess for Display.
But for debugging, a standard inspected form is fine, so Debug prints the contents in a consistent developer-friendly way.
Syntax and Examples
The most important syntax is:
println!("{:?}", value); // Debug
println!("{:#?}", value); // Pretty Debug
println!("{}", value); // Display
Printing a vector with Debug
fn main() {
let v = vec![1, 2, 3];
println!("{:?}", v);
}
Output:
[1, 2, 3]
Pretty-printing a vector
fn main() {
let v = vec![1, 2, 3];
println!("{:#?}", v);
}
Output:
[
1,
2,
3,
]
Creating custom display output
If you want output like 1, 2, 3, you can format the elements yourself:
fn main() {
let v = vec![1, 2, 3];
let text = v.iter()
.map(|n| n.to_string())
.collect::<Vec<_>>()
.join(", ");
println!("{}", text);
}
Output:
1, 2, 3
Wrapper type for reusable Display
use std::fmt;
struct DisplayVec<T>(Vec<T>);
impl<T: fmt::Display> fmt::Display for DisplayVec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
for (i, item) in self.0.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
}
write!(f, "]")
}
}
fn main() {
let v = DisplayVec(vec![1, 2, 3]);
println!("{}", v);
}
This works because DisplayVec is your own type, so Rust allows you to implement Display for it.
Step by Step Execution
Consider this example:
fn main() {
let v = vec![1, 2, 3];
println!("{:?}", v);
}
Step by step
vec![1, 2, 3]creates aVec<i32>.println!sees the format string"{:?}".{:?}tells Rust: use theDebugtrait.Vec<i32>implementsDebug, so formatting succeeds.- Rust prints the vector in debug form:
[1, 2, 3].
Now compare it with this failing version:
fn main() {
let v = vec![1, 2, 3];
println!("{}", v);
}
What changes?
println!sees"{}".{}tells Rust: use theDisplaytrait.Vec<i32>does not implementDisplay.- Compilation stops with error
E0277.
So the issue is not with vectors themselves. The issue is that the chosen formatting placeholder does not match the trait the type supports.
Real World Use Cases
Printing vectors appears in many practical Rust tasks:
Logging intermediate data
When debugging APIs, parsers, or algorithms, developers often inspect vectors:
println!("Parsed tokens: {:?}", tokens);
Inspecting query or processing results
A function may return a list of records, IDs, or errors:
println!("Matching IDs: {:?}", ids);
Pretty-printing nested data during development
When vectors contain structs or nested collections, {:#?} is easier to read:
println!("{:#?}", results);
Building user-facing output
If you are printing data for users, you usually do not rely on Debug. Instead, you format the output explicitly:
let names = vec!["Alice", "Bob", "Cara"];
println!("Users: {}", names.join(", "));
In real applications, Debug is mostly for developers, while custom formatting is used for reports, CLI output, and UI text.
Real Codebase Usage
In real Rust codebases, developers usually follow these patterns:
Use Debug for quick inspection
During development, Vec<T> is often printed with {:?} in:
- temporary debugging statements
- tests
- logs
- prototypes
dbg!(&items);
println!("Loaded items: {:?}", items);
Format user output explicitly
For command-line tools or messages shown to users, teams usually choose a deliberate format:
let output = values
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ");
println!("Values: {}", output);
Use wrapper types for reusable formatting
If the same vector formatting is needed in many places, a wrapper type is common:
struct CsvVec<T>(Vec<T>);
Then Display can be implemented once and reused.
Use Debug bounds in generic code
In generic helper functions, developers often require T: Debug when they only need inspectable output:
use std::fmt::Debug;
fn log_items<T: Debug>(items: &[T]) {
println!("{:?}", items);
}
Prefer slices in APIs when ownership is unnecessary
A lot of printing helpers take &[T] instead of Vec<T> because they only need to read elements:
fn print_numbers(nums: &[i32]) {
println!("{:?}", nums);
}
This makes the code more flexible and works with vectors, arrays, and slices.
Common Mistakes
Mistake 1: Using {} for a vector
Broken code:
fn main() {
let v = vec![1, 2, 3];
println!("{}", v);
}
Why it fails:
{}requiresDisplayVec<T>does not implementDisplay
Fix:
println!("{:?}", v);
Mistake 2: Assuming Debug is good for user-facing output
This works:
println!("{:?}", vec!["Alice", "Bob"]);
But the output may not be the style you want for end users.
Better:
let names = vec!["Alice", "Bob"];
println!("{}", names.join(", "));
Mistake 3: Trying to implement Display directly for Vec<T>
Broken idea:
use std::fmt;
impl<T: fmt::Display> fmt::Display for Vec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "...")
}
}
Why it fails:
Displayis from the standard libraryVec<T>is also from the standard library- Rust does not let you implement a foreign trait for a foreign type
Use a wrapper type instead.
Mistake 4: Forgetting element formatting requirements
If you build custom output, each element must itself be printable.
Example:
let text = values
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ");
This requires the element type to support Display.
Mistake 5: Confusing Debug and Display
A type can implement:
- both
DebugandDisplay - only
Debug - only
Display(less common)
Always match the placeholder to the trait:
{}→Display{:?}→Debug
Comparisons
| Feature | Display | Debug |
|---|---|---|
| Placeholder | {} | {:?} |
| Purpose | User-facing output | Developer-facing output |
| Intended style | Clean, readable | Inspectable, diagnostic |
Implemented for Vec<T> | No | Yes |
| Pretty-print option | No built-in equivalent | {:#?} |
| Good for logs/tests | Sometimes | Yes |
| Good for final CLI/UI text | Yes | Usually not |
{:?} vs {:#?}
| Formatter | Use case | Example output |
|---|---|---|
{:?} | Compact debug printing | [1, 2, 3] |
{:#?} | Multi-line readable debug output | `[ |
1,
2,
3,
]` |
Custom formatting vs Debug
| Approach | Best when | Trade-off |
|---|---|---|
{:?} | You want quick inspection | Output style is fixed |
join(", ") or manual formatting | You want user-friendly text | More code |
Wrapper + Display | You need reusable formatting | Requires a custom type |
Cheat Sheet
println!("{}", value)usesDisplayprintln!("{:?}", value)usesDebugprintln!("{:#?}", value)uses prettyDebugVec<T>implementsDebugVec<T>does not implementDisplay- You cannot implement
DisplayforVec<T>directly because of Rust's orphan rules - For custom vector output:
- format elements manually
- or create a wrapper type and implement
Display
Common patterns
let v = vec![1, 2, 3];
println!("{:?}", v);
println!("{:#?}", v);
let text = v.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(", ");
println!("{}", text);
Rule of thumb
- Use
{:?}for debugging - Use custom formatting for user-facing output
- Use a wrapper type if you need reusable
Displaybehavior
FAQ
Why can't I print a Vec with {} in Rust?
Because {} requires the Display trait, and Vec<T> does not implement Display.
How do I print a vector in Rust?
Use {:?} for debug output:
println!("{:?}", my_vec);
What is the difference between Display and Debug in Rust?
Display is for clean user-facing output. Debug is for programmer-facing inspection.
Can I implement Display for Vec<T> myself?
No, not directly. Rust's orphan rules prevent implementing a foreign trait for a foreign type. Use a wrapper type instead.
What does {:#?} do in Rust?
It pretty-prints Debug output across multiple lines, which is useful for complex or nested data.
Should I use Debug output in production apps?
It is fine for logs and diagnostics, but for user-visible output you should usually create a custom format.
Does every type implement Debug in Rust?
No. Many standard types do, but not all custom types automatically do unless you derive or implement Debug.
Is a slice printable the same way as a vector?
Usually yes for debug formatting. Both slices and vectors can be printed with {:?} when their element type supports Debug.
Mini Project
Description
Build a small Rust program that prints a list of tasks in two ways: a developer-friendly debug view and a clean user-facing view. This demonstrates when to use Debug and when to build custom formatting instead of relying on Display for Vec<T>.
Goal
Create a program that stores tasks in a vector, prints the raw vector with Debug, and then prints a custom comma-separated string for users.
Requirements
- Create a vector of at least three task names.
- Print the vector once using
{:?}. - Print the tasks again in a user-friendly comma-separated format.
- Include a wrapper type or helper function for reusable formatting.
Keep learning
Related questions
Absolute Values in Rust: Using the abs() Method
Learn how to calculate absolute values in modern Rust with abs(), handle signed integer overflow, and choose safer alternatives.
Accepting Iterators in Rust Functions with impl Iterator
Learn how to write Rust functions that accept HashMap iterators using generic bounds or impl Iterator, avoiding trait object and lifetime errors.
Access Enum Variant Values in Rust with Pattern Matching
Learn how to extract and print values stored in Rust enum variants using match and if let pattern matching, with practical examples.