TL;DR
Rustのprintln!
のフォーマット指定についての記事です。
長い記事でもありませんが、以下のソースを見れば大体わかります。
https://gist.github.com/YusukeHosonuma/6ee32ade9ac88cbc9fbd6b494154c5a0
はじめに
最近「Rustはいいぞ!」という声を聞いたり、Swiftが影響を受けた言語がRustだったりと、気になったので勉強し始めました。
Rustで標準出力はprintln!
マクロで行うのですが、フォーマット指定がC言語などのprintf
とは異なります。
以下のあたりのドキュメントに詳しく書かれているのですが、自分でコードを書いていて迷ったりすることもあったのでまとめてみました。(網羅はしていません)
基本
-
println!
で標準出力 -
{}
がプレースホルダ -
format!
でフォーマット後の文字列を取得(指定方法は同じ) - どちらもマクロで実装されている
- なので実行時のオーバーヘッドが(C言語のprintfよりは)少ない(はず)
- ただコンパイルエラーメッセージがわかりづらいことがある
println!("Hello world!");
println!("Hello {}!", "world");
let s = format!("Hello, {} !!", "Rust"); // s = "Hello, Rust !!"
プレースホルダ
-
{}
が基本で引数が順に埋められる -
{n}
で n番目(0始まり)の引数で置き換える -
{name}
でname="value"
と指定した引数で置き換えられる
println!("{} | {} | {1} | {three} | {four}",
"One",
"Two",
three="three",
four=4);
// => One | Two | Two | three | 4
揃え(Align)
-
:
の後に条件を指定 -
<n
が n桁で左寄せ -
>n
が n桁で右寄せ -
^n
が n桁で中央寄せ -
>0n
または<0n
で「0埋め」
println!("{0: <8} | {1: >8} | {2: ^8} | {3: <08} | {4: >08} | {hundred: >08}",
"Left",
"Right",
"Center",
42,
999,
hundred=100);
// => Left | Right | Center | 42000000 | 00000999 | 00000100
基数 / 小数点
-
b
がバイナリ表現 -
o
が8進数 -
x
が16進数(X
で大文字出力) -
e
が指数表現(E
で大文字出力)
println!("{:b}", 1234); // => 10011010010
println!("{:o}", 1234); // => 2322
println!("{:x}", 1234); // => 4d2
println!("{:X}", 1234); // => 4D2
println!("{:e}", 12.34); // => 1.234e1
println!("{:E}", 12.34); // => 1.234E1
fmt::Display / fmt::Debug
-
{}
ではfmt::Display
の実装が使われ -
{:?}
ではfmt::Debug
の実装が使われる
// 構造体の宣言
struct Point {
x: i32,
y: i32,
}
// fmt::Display トレイトの実装
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
// fmt::Debug トレイトの実装
impl fmt::Debug for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Point(x: {}, y: {})", self.x, self.y)
}
}
let p = Point { x: 1, y: 2 };
println!("{}", p); // => (1, 2)
println!("{:?} ", p); // => Point(x: 1, y: 2)
終わり
Rustはいいぞ!