テストケース: List
要素をそれぞれ順番に処理しなければならない構造体に対して fmt::Display を実装するのは厄介です。問題は、それぞれの write! が fmt::Result を生成することです。これを適切に処理するには、_すべて_の結果を扱う必要があります。Rust はまさにこの目的のために ? 演算子を提供しています。
write! に対して ? を使うと、次のようになります。
// `write!` を試して、エラーになるか確認する。エラーになった場合は、
// そのエラーを返す。それ以外の場合は続行する。
write!(f, "{}", value)?;
? が使えるので、Vec に対して fmt::Display を実装するのは簡単です。
use std::fmt; // `fmt` モジュールをインポートする。 // `Vec` を含む `List` という名前の構造体を定義する。 struct List(Vec<i32>); impl fmt::Display for List { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // `List` 構造体に格納されている Vec<i32> への参照を作成する。 let vec = &self.0; write!(f, "[")?; // 反復のインデックスを `index` として列挙しながら、 // `vec` 内の `v` を反復処理する。 for (index, v) in vec.iter().enumerate() { // 最初の要素を除くすべての要素に、カンマを追加する。 // エラー時に return するために ? 演算子を使う。 if index != 0 { write!(f, ", ")?; } write!(f, "{}", v)?; } // 開いた角括弧を閉じ、fmt::Result 値を返す。 write!(f, "]") } } fn main() { let v = List(vec![1, 2, 3]); println!("{}", v); }
演習
ベクター内の各要素のインデックスも出力されるように、プログラムを変更してみてください。新しい出力は次のようになるはずです。
[0: 1, 1: 2, 2: 3]