// dictionary
Debugトレイト.
Debugは、値の中身を開発者向けに表示するための標準ライブラリのトレイトです(std::fmt::Debug)。コンソール出力の{:?}はこのトレイトの実装を呼び出す指定で、{:#?}と書くと整形された複数行で表示されます1。
要求されるメソッドはfmtの1つだけですが、実装はderive属性(#[derive(Debug)])に任せるのが基本です2。デバッグを助けることが目的のトレイトのため、std公式ドキュメントはすべての公開型に実装することを推奨しています1。
#[derive(Debug)]
struct Book {
title: String,
price: u32,
}
#[derive(Debug)]
enum Payment {
Cash,
Credit(String),
}
fn main() {
let book = Book {
title: String::from("Rust入門"),
price: 3200,
};
println!("{:?}", book); // Book { title: "Rust入門", price: 3200 }
println!("{:#?}", book); // 1フィールド1行に整形して表示される
println!("{:?}", Payment::Cash); // Cash
println!("{:?}", Payment::Credit(String::from("JCB"))); // Credit("JCB")
}Playgroundで開く導出される出力の形式
#[derive(Debug)]が生成する表示は、型の名前とフィールドの値を機械的に並べたものです3。
| 対象 | 出力の形 | 例 |
|---|---|---|
| 構造体 | 型名 + { フィールド名: 値, ... } |
Book { title: "Rust入門", price: 3200 } |
| データを持たない列挙型のバリアント | バリアント名だけ | Cash |
| 名前付きフィールドを持たないバリアント・タプル構造体 | 名前 + (値, ...) |
Credit("JCB") |
| 名前付きフィールドを持つバリアント | 名前 + { フィールド名: 値, ... } |
Credit { brand: "JCB" } |
各フィールドの値もそれぞれのDebug実装で表示されます。文字列型や文字列スライスの値はクオートで囲まれ、改行や"は\n・\"とエスケープされた形で出ます1。
補足
Debugが要求される場面
Debugは表示のためだけでなく、標準ライブラリの各所でトレイト境界として要求されます。
| 場面 | 要求される理由 |
|---|---|
Result型のunwrap・expect |
失敗時にErrの中身をパニックのメッセージに出すため(E: Debug)5 |
assert_eq!などのテスト用マクロ |
値が一致しなかったときに両辺を表示するため6 |
dbg! |
式の値を、ソース位置とともに標準エラー出力へ表示するため7 |
「{:?}を書いていないのにDebugを実装しろと言われる」ときは、たいていこれらが原因です。なおdbg!は渡した式の所有権を奪うため、値を使い続けたい場合はdbg!(&value)と借用を渡します7。
表示内容を自分で決める(debug_struct)
形式を制御したい場合はfmtを手で実装します。Formatterのdebug_structビルダーを使うと、フィールドを並べるだけでderiveと同じ体裁になります8。{:#?}を指定したときの整形にもそのまま対応します(Rust 1.93で確認)。
use std::fmt;
struct Book {
title: String,
price: u32,
}
impl fmt::Debug for Book {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Book")
.field("title", &self.title)
.field("price", &format_args!("{}円", self.price))
.finish()
}
}
fn main() {
let book = Book {
title: String::from("Rust入門"),
price: 3200,
};
println!("{:?}", book); // Book { title: "Rust入門", price: 3200円 }
}Playgroundで開くformat_args!で包んだ値はクオートなしでそのまま埋め込まれます。
出力の形式に依存してはいけない
deriveが生成するDebugの出力も、標準ライブラリが提供する型のDebug実装も安定した仕様ではなく、将来のRustで変わる可能性があります9。出力を文字列として解析したり、テストで完全一致を期待したりするコードは避け、あくまで人が読むためのものとして扱います。
16進数で表示する
{:x?}・{:X?}と書くと、Debug表示に含まれる整数型の値を小文字・大文字の16進数で出力できます10。バイト列を確認するときに便利です。
fn main() {
let bytes = [255u8, 16, 1];
println!("{:?}", bytes); // [255, 16, 1]
println!("{:x?}", bytes); // [ff, 10, 1]
println!("{:X?}", bytes); // [FF, 10, 1]
}Playgroundで開くFootnotes
-
std公式ドキュメント — Module std::fmt “
fmt::Debugimplementations should be implemented for all public types. … The purpose of theDebugtrait is to facilitate debugging Rust code. In most cases, using#[derive(Debug)]is sufficient and recommended.” / alternate flag: “#?- pretty-print theDebugformatting (adds linebreaks and indentation)” / エスケープの例: “assert_eq!(format!("{} {:?}", "foo\n", "bar\n"), "foo\n \"bar\\n\"");” ↩ ↩2 ↩3 -
std公式ドキュメント — Trait Debug トレイト定義は
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>の1メソッドのみ。“Generally speaking, you should justderiveaDebugimplementation.” ↩ -
std公式ドキュメント — Trait Debug “This trait can be used with
#[derive]if all fields implementDebug. When derived for structs, it will use the name of the struct, then{, then a comma-separated list of each field’s name andDebugvalue, then}. For enums, it will use the name of the variant and, if applicable,(, then theDebugvalues of the fields, then).” なお、タプル構造体と、名前付きフィールドを持つバリアントの形式は同ドキュメントに明記がなく、実際の出力(Rust 1.93で確認)に基づく。 ↩ -
std公式ドキュメント — Trait Display “
Displayis similar toDebug, butDisplayis for user-facing output, and so cannot be derived.” ↩ -
std公式ドキュメント — Result::unwrap
unwrap・expectはimpl<T, E: Debug> Result<T, E>に定義されている。“Panics if the value is anErr, with a panic message provided by theErr’s value.” ↩ -
std公式ドキュメント — Macro assert_eq! “On panic, this macro will print the values of the expressions with their debug representations.” ↩
-
std公式ドキュメント — Macro dbg! “Prints and returns the value of a given expression for quick and dirty debugging.” “The macro works by using the
Debugimplementation of the type of the given expression to print the value to stderr along with the source location of the macro invocation as well as the source code of the expression.” “Invoking the macro on an expression moves and takes ownership of it before returning the evaluated expression unchanged. If the type of the expression does not implementCopyand you don’t want to give up ownership, you can instead borrow withdbg!(&expr)for some expressionexpr.” ↩ ↩2 -
std公式ドキュメント — Formatter::debug_struct “Creates a
DebugStructbuilder designed to assist with creation offmt::Debugimplementations for structs.” ↩ -
std公式ドキュメント — Trait Debug “Derived
Debugformats are not stable, and so may change with future Rust versions. Additionally,Debugimplementations of types provided by the standard library (std,core,alloc, etc.) are not stable, and may also change with future Rust versions.” ↩ -
std公式ドキュメント — Module std::fmt “
x?⇒Debugwith lower-case hexadecimal integers” / “X?⇒Debugwith upper-case hexadecimal integers” ↩
この辞書が使われているページ
backlinks 3