フォーマットして出力

Printing is handled by a series of macros defined in std::fmt some of which are:

  • format!:フォーマットされたテキストをStringに書き込みます。
  • print!format!と同様ですが、コンソール (io::stdout) にそのテキストを出力します。
  • println!print!と同じですが改行が付け加えられます。
  • eprint!format!と同様ですが、標準エラー出力 (io::stderr) にそのテキストを出力します。
  • eprintln!eprint!と同じですが改行が付け加えられます。

すべて同じやり方でテキストをパースし、正しくフォーマットできるかコンパイル時にチェックします。

fn main() {
    // 一般的に`{}`はどんな引数であろうと自動的に置き換えられます。
    // 例えば以下は文字列に変換されます。
    println!("{} days", 31);

    // 位置引数を利用できます。
    // `{}`の内側に整数を指定することで、どの引数で置換されるかが決まります。
    // 引数は0から始まります。
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");

    // 名前での指定も可能です。
    println!("{subject} {verb} {object}",
             object="the lazy dog",
             subject="the quick brown fox",
             verb="jumps over");

    // `:`のあとにフォーマット文字を指定して
    // 異なるフォーマットにすることも可能です。
    println!("Base 10:               {}",   69420); // 69420
    println!("Base 2 (binary):       {:b}", 69420); // 10000111100101100
    println!("Base 8 (octal):        {:o}", 69420); // 207454
    println!("Base 16 (hexadecimal): {:x}", 69420); // 10f2c

    // 特定の幅に右詰めすることもできます。この出力は "    1" になります。
    // (4つの空白と"1"で合計幅は5です)
    println!("{number:>5}", number=1);

    // 数字を0埋めすることもできます。
    println!("{number:0>5}", number=1); // 00001
    // 記号を反対にすると左寄せになり、"10000"が出力されます。
    println!("{number:0<5}", number=1); // 10000

    // フォーマット指定子の中に`$`をつけることで名前付き引数を利用できます。
    println!("{number:0>width$}", number=1, width=5);

    // 引数の数が正しいかのチェックも行ってくれます。
    println!("My name is {0}, {1} {0}", "Bond");
    // FIXME ^ 不足している引数 "James" を追加しましょう。

    // `{}`でフォーマットできるのは、fmt::Displayを実装している型のみです。
    // ユーザーが定義した型はデフォルトではfmt::Displayを実装していません。

    #[allow(dead_code)] // 未使用モジュールを警告する`dead_code`を無効化。
    struct Structure(i32);

    // `Structure`はfmt::Displayを実装していないので、
    // 以下はコンパイルできません。
    // println!("This struct `{}` won't print...", Structure(3));
    // TODO ^ この行をアンコメントしてみましょう。

    // Rust 1.58以上では、周囲の変数から直接引数に取ることができます。
    // 上で見たように、以下のコードは4つのスペースと1を、"    1" と出力します。
    let number: f64 = 1.0;
    let width: usize = 5;
    println!("{number:>width$}");
}

std::fmtはいくつものトレイトを持ち、それによってどのようにディスプレイに表示されるかが決まります。特に大事な形式は以下の2つです。

  • fmt::Debug{:?}というマーカーを使用し、デバッグ目的に使われます。
  • fmt::Display{}というマーカーを使用し、より美しく、ユーザフレンドリーに表示します。

この例で用いられている型は、標準ライブラリに含まれているため、ここではfmt::Displayを使用しています。カスタム型をテキストとして表示する場合は、さらに手順が必要です。

fmt::Displayトレイトを実装すると、自動的にToStringトレイトが実装されます。これによりString型への型変換ができるようになります。

43行目#[allow(dead_code)]は、直後のモジュールにのみ適用されるアトリビュートです。

演習

  • 上の例(FIXME を参照)を実行した際に生じるエラーを修復しましょう。
  • Structure構造体をフォーマットする行をアンコメントしてみましょう。(TODO を参照)
  • println!マクロを追加し、表示される小数部の桁数を調整してPi is roughly 3.142という文字列を出力しましょう。ただし、円周率の値はlet pi = 3.141592を使ってください。(ヒント:小数部の桁数を調整する方法については、std::fmtをチェックする必要があるかもしれません。)

参照

std::fmt, マクロ, 構造体, トレイト, dead_code