#println!
こんな感じで画面に文字を表示できます。
fn main(){
println!("画面に出力する文字列");
}
画面表示に関わっているのは以下のコードです。
println!
は文字列をコンソール(黒い文字だけの画面)に出力して、その後改行します。
println!("画面に出力する文字列");
Rustでは文字列はダブルクォーテーション"
で囲います。ダブルクォーテーションで囲めばそれは文字列として認識され、内容はRustの構文として認識されません。
##プレースホルダ
数値などを表示したい場合はプレースホルダを使います。
fn main(){
//{}がプレースホルダ。文字列の後にカンマで区切って数値などのデータを書く。
println!("3 * 4 + 2 = {}",3 * 4 + 2);
}
//実行結果:3 * 4 + 2 = 14
カンマ ,
の後に書いた数値がプレースホルダの位置に挿入されています。
##書式の指定
format!
マクロやprint!
println!
等のマクロはプレースホルダの中({
と}
の間)に書式を書くと、書式を指定することが出来ます。
plintln!
マクロのフォーマット機能はstd::fmtのrustdocで詳細を確認できます。
フォーマット文字列は以下の構文で記述します。
format_string := <text> [ maybe-format <text> ] *
maybe-format := '{' '{' | '}' '}' | <format>
format := '{' [ argument ] [ ':' format_spec ] '}'
argument := integer | identifier
format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
fill := character
align := '<' | '^' | '>'
sign := '+' | '-'
width := count
precision := count | '*'
type := identifier | '?' | ''
count := parameter | integer
parameter := argument '$'
これはたぶんBNFでしょう。
:=
の右側の通りに記号を並べると左辺の記号として認識されます。
|
は記号の並びに複数のパターンがあることを表します。|
を区切りとしてどれか一つが左辺の記号として認識されます。
書式を指定しているのはformat_spec
(空行の次にある最も長い行)です。
format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
たくさんのオプションが用意されています。順にみていきます。
##[[fill]align] - アライメントと空白を埋める文字の指定
右寄せ・中央・左寄せの指定と、空白を埋める文字を指定します。
位置を指定する場合は文字列の最小幅である[width]
の指定もセットになると思います。
以下は5桁、空白を-
で埋めるの書式です。5桁以上の場合はすべての桁が表示されます。
後述しますが、数値の場合の0埋めは[fill]
で行うと符号やプレフィックスまで移動するので[`0`]
のほうが適しています。
fn main(){
println!("「{:->5}」", 3); // 「----3」
println!("「{:-^5}」", 3); // 「--3--」
println!("「{:-<5}」", 3); // 「3----」
println!("「{:->5}」", 1234567); // 「1234567」
println!("「{:-^5}」", 1234567); // 「1234567」
println!("「{:-<5}」", 1234567); // 「1234567」
}
##[sign] - 符号+
を省略せずに表示する
符号を表示できます。
しかし、-
は現在(2020/3/7)使われていないようです。
数値がマイナスの値であれば-
がつくのであまり問題にはならないでしょう。
[sign]
と[width]
を組み合わせる場合は符号の位置に気を付けてください。
fn main(){
println!("「{:+}」", 123); // 「+123」 「+」の表示を強制する
println!("「{:+}」", -123); // 「-123」 マイナスの時はちゃんと「-」がつきます
println!("「{:0>+7}」",123); // 「000+123」 テキスト処理的なゼロ埋め
println!("「{:+07}」", 123); // 「+000123」 数学的?なゼロ埋めはwidthの前に0を書く
}
##[#] - プレフィックス・改行・インデントを整える
[type]
と併用して使います。プレフィックスを付けたり、改行やインデントを入れたりする機能です。
[`#`]
に対応していない[type]
もあります。
Rustdocに一覧が記載されています。
#? - プリティプリント(改行やインデントなどで形を整えた状態)のデバッグフォーマット
#x - 0xで始まる16進数表示 小文字
#X - 0xで始まる16進数表示 大文字
#b - 0bで始まる2進数表示
#o - 0oで始まる8進数表示
これらの他にも以下の記載が使用できました。2進数、8進数はダメでした。
#x? - プリティプリントのデバッグフォーマットで数値が16進数表示 小文字
#X? - プリティプリントのデバッグフォーマットで数値が16進数表示 大文字
####?
デバッグフォーマットといいます。
データの構造と値を文字列に変換することが出来ます。
#[derive(Debug)] // これを直前に書くとデバッグフォーマットが使えるようになる
struct Point {
x: i32,
y: i32,
}
fn main() {
let origin = Point { x: 123, y: 456 };
println!("The origin is: {:?}", origin); // ただのデバッグフォーマット
println!("The origin is: {:x?}", origin); // デバッグフォーマットで、数値が16進数表示(小文字)
println!("The origin is: {:#?}", origin); // 改行とインデント付きの(プリティプリントの)デバッグフォーマット
println!("The origin is: {:#X?}", origin); // プリティプリントのデバッグフォーマットで、数値が16進数表示(大文字)
}
実行結果
The origin is: Point { x: 123, y: 456 }
The origin is: Point { x: 7b, y: 1c8 }
The origin is: Point {
x: 123,
y: 456,
}
The origin is: Point {
x: 0x7B,
y: 0x1C8,
}
####x,#X,#b,#o
〇〇進数表示でプレフィックスがつきます。
fn main() {
println!("「{:#x}」", 123); // 「0x7b」
println!("「{:#X}」", 123); // 「0x7B」
println!("「{:#b}」", 123); // 「0b1111011」
println!("「{:#o}」", 123); // 「0o173」
}
##['0'][width] - 最小幅の指定と0埋め
[width]
は変換後の文字列の最小幅を指定するものです。
[`0`]
は[width]
の幅に満たない場合にゼロ埋めすることを指定するフラグです。
[[fill]align]
の[fill]
でも[width]
の幅に満たない部分の文字を指定できますが、符号やプレフィックスの位置が異なります。数値として表示する場合は[fill]
ではなく[`0`]
が適しています。
fn main(){
println!("「{:10}」", 123); // 「 123」 widthに10文字を指定
println!("「{:010}」", 123); // 「0000000123」 widthに10文字を指定 ゼロ埋め
// fillで0を指定した場合と`0`の違い 符号やプレフィックスの位置に注目
println!("「{:+010}」", -123.456); // 「-00123.456」ゼロ埋め
println!("「{:0>+10}」", -123.456); // 「00-123.456」>の前に0があるためfillと判定される
println!("「{:#010b}」", 5); // 「0b00000101」 ゼロ埋め
println!("「{:0>#10b}」", 5); // 「000000b101」 これは2進数だが、16進数と区別ができない
}
##['.' precision] - 小数点以下の桁数を指定する
これは浮動小数点数の小数点以下の桁数を指定します。
fn main(){
println!("「{:.3}」", 123.456789); // 「123.457」 小数点以下4桁以降が丸められた
println!("「{:.3}」", 100.0004); // 「100.000」 四捨
println!("「{:.3}」", 100.0005); // 「100.001」 五入
}
##[type] - フォーマットの種類を指定する(16進数や指数表示など)
フォーマットの種類を指定します。何も書かなければdisplay
になります。
Rustdocに[type]
とそれに対応するトレイトの一覧が乗っています。
各トレイトにfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
関数が定義されており、これを実装するとユーザー定義型のデータをフォーマットできるようになります。
Debug
は#[derive(Debug)]
を書くだけで実装されます。
nothing ⇒ Display
? ⇒ Debug
x? ⇒ Debug with lower-case hexadecimal integers
X? ⇒ Debug with upper-case hexadecimal integers
o ⇒ Octal
x ⇒ LowerHex
X ⇒ UpperHex
p ⇒ Pointer
b ⇒ Binary
e ⇒ LowerExp
E ⇒ UpperExp
fn main() {
println!("「{}」", "Display"); // 「Display」 Displayではデータの中身だけを表示
println!("「{:?}」", "Debug"); // 「"Debug"」 Debugではリテラルと同じ表示になる
println!("「{:x?}」", 123); // 「7b」
println!("「{:X?}」", 123); // 「7B」
println!("「{:o}」", 123); // 「173」
println!("「{:x}」", 123); // 「7b」
println!("「{:X}」", 123); // 「7B」
println!("「{:p}」", &123); // 「0x7ff6d7312348」 ポインタ 要するにアドレス
println!("「{:b}」", 123); // 「1111011」
println!("「{:e}」", 123.456); // 「1.23456e2」
println!("「{:E}」", 123.456); // 「1.23456E2」
}