如何打印 Vec?

我试了下面的代码:

fn main() {
let v2 = vec![1; 10];
println!("{}", v2);
}

但编译器抱怨道:

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`

有人为 Vec<T>实现了这个特性吗?

87758 次浏览
let v2 = vec![1; 10];
println!("{:?}", v2);

{}用于字符串和其他可以直接显示给用户的值。向用户显示矢量没有单一的方法。

{:?}格式化程序可以用来调试它,它看起来像:

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

Display是提供 {}后面的方法的特性,而 Debug{:?}的特性

有人为 Vec<T>实现这个特性吗?

没有。

令人惊讶的是,这是一个明显正确的答案; 这是罕见的,因为证明事物的缺失通常是困难的或不可能的。我们怎么能如此确定?

Rust 有非常严格的一致性规则,impl Trait for Struct只能做到:

  • 要么和 Trait在同一个箱子里
  • 或者和 Struct放在同一个箱子里

没有别的地方; 让我们看看 试试看:

impl<T> std::fmt::Display for Vec<T> {
fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
Ok(())
}
}

收益率:

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src/main.rs:1:1
|
1 | impl<T> std::fmt::Display for Vec<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter

此外,要使用 trait,它需要在作用域中(因此,您需要链接到它的 crate) ,这意味着:

  • 你与 Display的板条箱和 Vec的板条箱都有联系
  • 也不为 Vec实现 Display

因此我们得出结论,没有人为 Vec实现 Display


正如 Manishearth 指出的那样,作为一种解决方案,你可以使用 Debug trait,它可以通过 "{:?}"作为格式说明符来调用。

如果您知道向量包含的元素的类型,您可以创建一个以向量作为参数的结构,并为该结构实现 Display

use std::fmt::{Display, Formatter, Error};


struct NumVec(Vec<u32>);


impl Display for NumVec {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let mut comma_separated = String::new();


for num in &self.0[0..self.0.len() - 1] {
comma_separated.push_str(&num.to_string());
comma_separated.push_str(", ");
}


comma_separated.push_str(&self.0[self.0.len() - 1].to_string());
write!(f, "{}", comma_separated)
}
}


fn main() {
let numbers = NumVec(vec![1; 10]);
println!("{}", numbers);
}

是否有任何理由不将向量的内容项按以前收集的项目写入? *)

use std::fmt::{Display, Formatter, Error};


struct NumVec(Vec<u32>);


impl Display for NumVec {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let v = &self.0;
if v.len() == 0 {
return Ok(());
}
for num in &v[0..v.len() - 1] {
if let Err(e) = write!(f, "{}, ", &num.to_string()) {
return Err(e);
}
}
write!(f, "{}", &v[v.len() - 1])
}
}


fn main() {
let numbers = NumVec(vec![1; 10]);
println!("{}", numbers);
}

*)不,没有。

因为我们想要显示一些东西,所以 Display trait 肯定是实现了的。所以这是正确的 Rust 因为: ,医生说关于 ToString trait:

”对于实现 Display trait 的任何类型,都会自动实现此 trait。因此,ToString不应该直接实现: 应该实现 Display,而且 ToString的实现是免费的。”

特别是在空间有限的微控制器上,我肯定会采用这种解决方案,并立即进行编写。

从 Rust 1.58开始,有一种更简洁的方法来打印向量(或任何其他变量)。这使您可以将要打印的变量放在花括号中,而不需要将其放在末尾。对于打印向量所需的调试格式,您可以在大括号中添加 :?,如下所示:

fn main() {
let v2 = vec![1; 10];
println!("{v2:?}");
}

有时候你不想用一些类似于公认答案的东西

let v2 = vec![1; 10];
println!("{:?}", v2);

因为您希望使用每个元素的 Display特性来显示,而不是使用它的 Debug特性; 但是,如前所述,由于 Rust 的一致性规则,您不能在 Vec上实现 Display。您可以使用如下函数实现一个更通用的解决方案,而不是使用 Display trait 实现一个包装器结构:

use std::fmt;


pub fn iterable_to_str<I, D>(iterable: I) -> String
where
I: IntoIterator<Item = D>,
D: fmt::Display,
{
let mut iterator = iterable.into_iter();


let head = match iterator.next() {
None => return String::from("[]"),
Some(x) => format!("[{}", x),
};
let body = iterator.fold(head, |a, v| format!("{}, {}", a, v));
format!("{}]", body)
}

它不需要将向量包装在结构中。只要 it实现 IntoIterator,而元素类型实现 Display,就可以调用:

println!("{}", iterable_to_str(it));