Как вывести вектор (Vec) на экран в Rust? Примеры с println! и форматированием
Основная проблема: трейты форматирования
Вы правы — ошибка возникает из-за того, что Vec<i32> не реализует трейт std::fmt::Display, который используется в макросе println! с фигурными скобками {}. Этот трейт предназначен для "человекочитаемого" вывода, но для коллекций вроде вектора он не определён по умолчанию.
Однако Rust предоставляет отличную альтернативу — трейт std::fmt::Debug, который используется с форматированием {:?}. Он реализован для большинства стандартных типов, включая Vec. Вот как это работает:
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
println!("Вектор: {:?}", numbers); // Вывод: [1, 2, 3, 4, 5]
// Для красивой печати с отступами используйте {:#?}
println!("Красивый вывод: {:#?}", numbers);
// Вывод:
// [
// 1,
// 2,
// 3,
// 4,
// 5
// ]
}
Поэлементный вывод с помощью итераторов
Если вам нужно вывести каждый элемент на новой строке или с произвольным форматированием, используйте итераторы:
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// Каждый элемент на новой строке
for num in &numbers {
println!("{}", num);
}
// С индексом
for (i, num) in numbers.iter().enumerate() {
println!("numbers[{}] = {}", i, num);
}
// В одну строку через запятую
let joined: Vec<String> = numbers.iter().map(|n| n.to_string()).collect();
println!("{}", joined.join(", "));
}
Создание своей функции для вывода
Для частого использования удобно написать вспомогательную функцию:
fn print_vec<T: std::fmt::Display>(vec: &[T]) {
print!("[");
for (i, item) in vec.iter().enumerate() {
if i > 0 {
print!(", ");
}
print!("{}", item);
}
println!("]");
}
fn main() {
let v = vec![10, 20, 30];
print_vec(&v); // Вывод: [10, 20, 30]
}
Для структур и пользовательских типов
Если у вас вектор структур, вы можете вывести его через Debug, добавив аннотацию:
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
fn main() {
let points = vec![Point { x: 0, y: 0 }, Point { x: 1, y: 2 }];
println!("{:#?}", points);
// Вывод:
// [
// Point {
// x: 0,
// y: 0,
// },
// Point {
// x: 1,
// y: 2,
// }
// ]
}
Итоговые рекомендации
- Для быстрой отладки — используйте
{:?}или{:#?}. Это самый простой способ. - Для красивого вывода пользователю — пишите цикл с нужным форматированием.
- Для сложных структур — выводите через
Debugили реализуйте свойDisplay. - Для векторов строк — отлично работает
join.
Помните: Vec — это просто контейнер, и способ его отображения зависит от вашей задачи. В Rust нет "волшебного" универсального вывода, но есть гибкие инструменты для любого случая.
Альтернативный подход: крейт pretty_assertions для тестов
Если вы пишете тесты и хотите красиво сравнивать векторы с выводом различий, рекомендую обратить внимание на крейт pretty_assertions. Он автоматически форматирует вывод при использовании макроса assert_eq!:
use pretty_assertions::assert_eq;
fn main() {
let expected = vec![1, 2, 3, 4, 5];
let actual = vec![1, 2, 3, 0, 5];
assert_eq!(expected, actual);
// Вывод покажет разницу с подсветкой:
// [
// 1,
// 2,
// 3,
// - 4,
// + 0,
// 5,
// ]
}
Кастомный трейт Display для вектора
Если вам нужно постоянно выводить векторы в определённом формате, можно реализовать свой трейт-обёртку:
use std::fmt;
struct PrettyVec<T>(Vec<T>);
impl<T: fmt::Display> fmt::Display for PrettyVec<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 = vec![10, 20, 30];
println!("{}", PrettyVec(v)); // Вывод: [10, 20, 30]
}
Этот подход удобен, когда нужно много раз выводить векторы в одном стиле, но он требует написания дополнительного кода. Для разовых задач проще использовать {:?} или циклы.