私は次のコードを試しました:
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>
にこの特性を実装している人はいますか?
誰でもこの特性を
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
さらに、特性を使用するには、範囲内にある必要があります(したがって、そのクレートにリンクする必要があります)。つまり、
Display
のクレートとVec
のクレートの両方にリンクされていますDisplay
のVec
も実装しませんしたがって、誰もDisplay
にVec
を実装していないと結論付けることになります。
回避策として、Manishearthが示すように、Debug
トレイトを使用できます。これは、"{:?}"
を介してフォーマット指定子として呼び出すことができます。
let v2 = vec![1; 10];
println!("{:?}", v2);
{}
は、ユーザーに直接表示できる文字列およびその他の値用です。ユーザーにベクターを表示する唯一の方法はありません。
{:?}
フォーマッタを使用してデバッグでき、次のようになります。
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Display
は{}
の背後にあるメソッドを提供する特性であり、Debug
は{:?}
用です
ベクトルに含まれる要素の型がわかっている場合は、引数としてベクトルを取る構造体を作成し、その構造体に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);
}
これもあなたのために働くはずのワンライナーです:
println!("[{}]", v2.iter().fold(String::new(), |acc, &num| acc + &num.to_string() + ", "));
ここ は実行可能な例です。
私の場合、関数呼び出しから_Vec<&str>
_を受け取っていました。関数のシグネチャをカスタムタイプ(Display
特性を実装できるもの)に変更したくありませんでした。
私の1つ目のケースでは、次のようにVec
の表示をprintln!()
で直接使用するワンライナーに変えることができました。
_println!("{}", myStrVec.iter().fold(String::new(), |acc, &arg| acc + arg));
_
(ラムダは、さまざまなデータ型で使用するために、またはより簡潔なDisplay
trait実装に適合させることができます。)