フォーマット出力

出力マクロ

Rustの印刷(出力)機能は std::fmt モジュール内に一連のマクロで実装されています。よく使用するマクロの説明は下記の通りです:

  • format!:フォーマットしたテキストを文字列に書き込む
  • print!:コンソール(標準出力)に内容を出力
  • println!print!と同じ、末尾に自動で改行が挿入される
  • eprint!:標準エラー出力ストリームに内容を出力
  • eprintln!eprint!と同じ、末尾に自動で改行

末尾にlnが付くマクロは改行文字が追加され、出力完了後に自動で行が切り替わります。

先頭に付くeはerrorの略称で、エラー情報を出力するために使用します

上記のすべてのマクロはフォーマット記法が完全に共通で、Rustはコンパイル段階でフォーマット記述の正当性を検証します。

使用例

基本プレースホルダー {}

{} は汎用の置換記号で、後から渡した引数を順番に埋め込み、自動的に文字列へ変換して出力します。

fn main() {
    println!("{} days", 31);
    // 出力:31 days
}Code language: JavaScript (javascript)

位置引数

{} 内部に数値インデックス(0から開始)を記述すると、任意の順番の引数を指定可能で、引数の再利用や順番の入れ替えに対応します。

fn main() {
    println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
    // 出力:Alice, this is Bob. Bob, this is Alice
}Code language: JavaScript (javascript)

上記の例から分かる通り、引数のインデックスは0・1・2…順番通りに使わなくても順番を自由に入れ替えられます。後ろに記述した引数”Alice”は0番、”Bob”は1番として割り当てられます。

名前付き引数

インデックスによる指定では分かりにくい場合、「名前付き引数」を利用できます。フォーマット文字列内に {引数名} を記述し、呼び出し時は 引数名=値 の形式で渡します。引数の記述順番に制限がなく可読性が向上します。

fn main() {
    println!("{subject} {verb} {object}",
         object="the lazy dog",
         subject="the quick brown fox",
         verb="jumps over");
    // 出力:the quick brown fox jumps over the lazy dog
}Code language: JavaScript (javascript)

後ろの各値に名前を割り当て、フォーマット文字列内で {引数名} と記述するだけで対応する値を呼び出せるため、直感的に分かりやすくなります。

基数変換フォーマット(:書式指定子

プレースホルダー内に : と書式文字を追加すると、数値を2進数・8進数・16進数などの各基数表記に変換可能です。

  • :b:2進数
  • :o:8進数
  • :x:小文字16進数
fn main() {
    println!("10進数:    {}",   69420);    // 69420
    println!("2進数:  {:b}", 69420);    // 10000111100101100
    println!("8進数:  {:o}", 69420);    // 207454
    println!("16進数:{:x}", 69420);    // 10f2c
}Code language: JavaScript (javascript)

幅指定・位置揃え・埋め文字

1 右揃え(>幅

{:>n} は全体の表示幅を n とし、内容を右揃え、左側を空白で埋めます。

fn main() {
	println!("{number:>5}", number=1);
	// 幅5、左に半角スペース4つを埋めて出力 →     1
}Code language: JavaScript (javascript)
2 0埋め揃え

揃え記号の前に 0 を記述すると、空白の代わりに数字0で余白を埋めます。

  • :0>5:右揃え、左側を0で埋め
  • :0<5:左揃え、右側を0で埋め
fn main() {
	println!("{number:0>5}", number=1); // 右揃え0埋め → 00001
	println!("{number:0<5}", number=1); // 左揃え0埋め → 10000
}Code language: JavaScript (javascript)

埋め文字は0以外の任意の文字に変更可能です。例として下記は左側を大文字Aで埋める例です

fn main() {
	println!("{number:A>5}", number=1); // 右揃えA埋め → AAAA1
	println!("{number:A<5}", number=1); // 左揃えA埋め → 1AAAA
}Code language: JavaScript (javascript)
3 動的幅指定(変数名$

幅を固定値ではなく、変数名$ で外部の名前付き引数または変数を参照し、動的に表示幅を制御できます。

つまり表示幅をコードに直書きせず、変数から動的に指定可能ということです。

fn main() {
	// 方法1:名前付き引数と併用
	println!("{number:0>width$}", number=1, width=8);

	// 方法2:コード内変数を直接参照(Rust 1.58以降対応)
	let number: f64 = 1.0;
	let width: usize = 8;
	println!("{number:>width$}"); // 出力:       1
}Code language: JavaScript (javascript)

コンパイル時引数検証

Rustはコンパイル段階でプレースホルダーの数と渡した引数の数が一致するかチェックし、引数が不足している場合はコンパイルエラーを出力します。

fn main() {
	// プレースホルダーが2つだが引数は1つのみ、コンパイル失敗
	println!("My name is {0}, {1} {0}", "Bond");
	// 修正:引数 "James" を追加
	println!("My name is {0}, {1} {0}", "Bond", "James");
}Code language: JavaScript (javascript)

コンパイル時エラーメッセージ:{1}の位置が無効、後ろに引数が1つしか渡されていないため

エラー:存在しない位置引数1を参照しています(現在渡された引数は1個のみ)
 --> D:\rustdemo\hello.rs:3:29
  |
3 |     println!("My name is {0}, {1} {0}", "Bond");
  |                                ^
  |
  = ヒント:位置引数は0から番号付けされます

エラー:コンパイルを中止、計1件のエラーCode language: JavaScript (javascript)

独自型のフォーマット制限

標準状態では {}fmt::Displayトレイトを実装した型のみフォーマット可能です。独自構造体は標準でこのトレイトが実装されていないため、そのまま {} で出力するとコンパイルエラーになります。

fn main() {
    struct Structure(i32);
	// 下記コードはコンパイルできない
    println!("{}", Structure(3));
}Code language: JavaScript (javascript)
エラー[E0277]:構造体 `Structure``std::fmt::Display` トレイトが実装されていません
 --> D:\rustdemo\hello.rs:4:20
4 |     println!("{}", Structure(3));
  |               --   ^^^^^^^^^^^^ この型は標準フォーマッタで出力できません
  |               |
  |               この書式引数は型にDisplayトレイトの実装を要求します

ヒント:`Structure` 構造体に `std::fmt::Display` トレイトが実装されていません
 --> D:\rustdemo\hello.rs:2:2
2 |     struct Structure(i32);
  |     ^^^^^^^^^^^^^^^^

補足説明:フォーマット文字列内では代わりに `{:?}`(または整形出力の`{:#?}`)を試してみてください
コンパイル中止、計1件のエラー。

エラー詳細を確認するにはコマンド:rustc --explain E0277 を実行してくださいCode language: JavaScript (javascript)

* 1 構造体を出力したい場合はDisplayトレイトを実装する必要があります(今は雰囲気だけ理解し、後ほど詳しく学びます)

use std::fmt;

struct Structure(i32);

// 構造体にDisplayトレイトを実装
impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // self.0 でタプル構造体内のi32値にアクセス
        write!(f, "数値:{}", self.0)
    }
}

fn main() {
    println!("{}", Structure(3));
}Code language: PHP (php)
* 2 一時的なデバッグ → デバッグ書式 {:?} / {:#?} を使用

プログラマーのデバッグ用途に適しています。正式な環境ではなく、単に構造体内の値を確認したい場合はDebugデバッグトレイトを使用できます

Rustは独自型に対し標準でデバッグトレイト Debug が実装されており、{:?} で出力可能です:

#[derive(Debug)]
#[allow(dead_code)] // 使用されていないコード/フィールドの警告を非表示
struct Structure(i32);

fn main() {
    println!("{:?}", Structure(3));
    println!("{:#?}", Structure(3));
}Code language: PHP (php)

* std::fmt 二つの核心フォーマットトレイト

std::fmt モジュールにはテキスト表示を制御する複数のトレイトが含まれ、よく使う二つは下記です:

  1. fmt::Debug はプレースホルダー {:?} と組み合わせ、デバッグ用途の出力に特化します。
  2. fmt::Display はプレースホルダー {} と組み合わせ、一般ユーザー向けに規範的で見やすい形式で内容を表示します。

標準ライブラリ内蔵型はこの二つのトレイトが標準実装されておりそのまま出力可能;独自型は直接使用できず、対応するトレイトを手動で実装する必要があります。

型に fmt::Display を実装すると自動的に ToString トレイトも実装され、当該型を文字列へ変換する機能が利用できるようになります。

#[allow(dead_code)]

#[allow(dead_code)] はコード属性で、直後のコード要素に作用し「未使用コード」の警告を遮断する役割です。

上記の例

fn main() {
    struct Structure(i32);
	// 下記コードはコンパイルできない
    //println!("{}", Structure(3));
}Code language: JavaScript (javascript)

2行目のprintln!(“{}”, Structure(3)); はエラーになるためコメントアウトしています。この状態で実行すると、

警告:構造体 `Structure` が一度も生成されません
 --> D:\rustdemo\hello.rs:2:12
  |
2 |     struct Structure(i32);
  |            ^^^^^^^^^
  |
  = 注記:`#[warn(dead_code)]``#[warn(unused)]` に含まれる)は標準で有効

警告:計1件の警告が出力されました
Code language: JavaScript (javascript)

このような警告が表示される理由は、struct Structure(i32); が一度も使用されていないためです。この警告を非表示にしたい場合は該当属性を追加します

fn main() {
	#[allow(dead_code)] 
    struct Structure(i32);
	// 下記コードはコンパイルできない
    //println!("{}", Structure(3));
}Code language: PHP (php)
浮動小数点数の小数桁指定

変数 pi = 3.141592 を定義し、フォーマット出力で小数第3位まで表示するコードを作成、出力内容:Pi is roughly 3.142

fn main() {
	let pi = 3.141592;
	println!("Pi is roughly {:.3}", pi);//3.142
	println!("Pi is roughly {0}", pi); //3.141592
}Code language: JavaScript (javascript)

Previous:
Next:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です