Debug トレイト
CoddyのRustジャーニー「Object Oriented Programming」セクションの一部 — レッスン 35/61。
Rustの標準ライブラリには、共通の機能を提供する定義済みのトレイトが数多く用意されています。開発において最も便利なものの1つはDebugトレイトで、これを使用すると構造体の内容を検査用に表示できます。
カスタム構造体を直接出力しようとすると、Rustはそれをどのように表示すればよいか分かりません:
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // エラー!Debugが実装されていません
{:?} フォーマッタは Debug トレイトを必要とします。手動で実装する代わりに、Rustはショートカットである #[derive] 属性を提供しています。これを構造体定義の直上に配置します:
#[derive(Debug)]
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Player { name: "Alice", score: 100 }
#[derive(Debug)] 属性は、コンパイラに Debug 実装を自動的に生成するように指示します。これは、構造体内のすべてのフィールドも Debug を実装している限り機能します(ほとんどの標準型は実装しています)。
入れ子構造を持つ出力をより読みやすくするために、プリティプリント(整形出力)には {:#?} を使用します:
println!("{:#?}", p);
// Player {
// name: "Alice",
// score: 100,
// }
Debug を派生させることは開発において不可欠です。これによって、カスタムのフォーマット用コードを記述することなく、データを素早く確認できるようになります。
チャレンジ
簡単Debug トレイトを継承(derive)して、構造体を検査可能にしましょう!デバッグ目的でアイテムを出力できる、シンプルな在庫管理システムを作成します。
コードは2つのファイルに分けて構成します:
inventory.rs: 2つのパブリックフィールド、name(String) とquantity(u32) を持つパブリックなItem構造体を定義します。#[derive(Debug)]属性を使用して、構造体に Debug トレイトを自動的に実装します。main.rs: inventory モジュールを取り込み、提供された入力を使用してItemインスタンスを作成します。デバッグフォーマッタ{:?}を使用してアイテムを出力し、その内部構造を表示します。
Debug を継承する利点は、Rust がフォーマット用のコードを自動的に生成してくれることです。手動で実装する必要はありません!構造体に属性を追加するだけで、{:?} で出力可能になります。
出力は、Rust のデバッグ形式でアイテムを表示する必要があります:
Item { name: "{name}", quantity: {quantity} }例えば、入力が Keyboard と 15 の場合:
Item { name: "Keyboard", quantity: 15 }2つの入力を受け取ります:アイテム名と数量(u32 としてパースしてください)。
チートシート
Debugトレイトを使用すると、{:?}フォーマッタを使用して、構造体の内容を検査用に表示できます。
#[derive(Debug)]属性を使用して、構造体にDebugを自動的に実装します。
#[derive(Debug)]
struct Player {
name: String,
score: u32,
}
let p = Player { name: String::from("Alice"), score: 100 };
println!("{:?}", p); // Player { name: "Alice", score: 100 }
より整った形式で整形された出力(プリティプリント)を行うには、{:#?}を使用します。
println!("{:#?}", p);
// Player {
// name: "Alice",
// score: 100,
// }
#[derive(Debug)]属性は、構造体のすべてのフィールドがDebugを実装している限り機能します。ほとんどの標準型はこれを実装しています。
自分で試してみよう
mod inventory;
use inventory::Item;
fn main() {
// 入力を読み込む
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
let mut quantity_str = String::new();
std::io::stdin().read_line(&mut quantity_str).expect("Failed to read line");
let quantity: u32 = quantity_str.trim().parse().expect("Failed to parse quantity");
// TODO: 指定された名前と数量でItemインスタンスを作成する
// TODO: デバッグフォーマッタ {:?} を使用してアイテムを表示する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。