Rust の文字列操作(2)

前回の続き。 Rust の文字列操作についてオベンキョ中です。

他の型の値を文字列に変換する

ある型が ToString トレイトを実装していれば to_string() メソッドを使って文字列に変換できる。 整数や浮動小数点数などの基本型は ToString トレイトを実装している。 以下のようにリテラル表現に対して直接 to_string() メソッドを起動することもできる。

fn main() {
    println!("{}", (123).to_string()); //Output: 123
    println!("{}", (1.23).to_string()); //Output: 1.23
    println!("{}", (true).to_string()); //Output: true
    println!("{}", ('あ').to_string()); //Output: あ
}

同じ基本型でもタプルや配列は ToString トレイトを実装していないため to_string() メソッドは使えない。

fn main() {
    println!("{}", ([1, 2, 3]).to_string()); //Error: no method named `to_string` found for type `[{integer}; 3]` in the current scope
}

変換する文字列を整形する

今までさんざん出てきたので今更だが, format! 等のマクロを使えば他の型の値を変換する際の文字列を整形できる。

マクロ名 機能
format! 文字列を整形して String として出力する
print!, println! 文字列を整形して標準出力に出力する
write!, writeln! 文字列を整形して指定したストリームに出力する
panic! 文字列を整形して panic 出力に付加する

たとえば,こんな感じ。

fn main() {
    println!("{{{} = {num:#04x} = {num:#010b}}}", num = 15); //Output: {15 = 0x0f = 0b00001111}
}

プレースホルダ {which:how} の中身の how の部分が C/C++ や Go の printf 文の書式(%d など)に相当する。 意味もだいたい同じ。

書式 意味
なし 既定のテキスト
b 2進数
o 8進数
x 16進数(小文字)
X 16進数(大文字)
e 浮動小数点数科学技術記法(小文字)
E 浮動小数点数科学技術記法(大文字)
? デバッグ出力
p ポインタ値

実はこれらの書式には対応するトレイトがあって,独自に作成した型でもトレイトを実装することで書式に対応できる。

書式 トレイト
なし std::fmt::Display
b std::fmt::Binary
o std::fmt::Octal
x std::fmt::LowerHex
X std::fmt::UpperHex
e std::fmt::LowerExp
E std::fmt::UpperExp
? std::fmt::Debug
p std::fmt::Pointer

たとえば,以下の構造体 Person に対して

struct Person {
    age: u32,
    name: String,
}

std::fmt::Display トレイトを実装してみる。 こんな感じ。

use std::fmt;

struct Person {
    age: u32,
    name: String,
}

impl fmt::Display for Person {
    fn fmt(&self, dest: &mut fmt::Formatter) -> fmt::Result {
        write!(dest, "{} ({})", self.name, self.age)
    }
}

fn main() {
    let p1 = Person {
        age: 24,
        name: "alice".to_string(),
    };
    println!("p1 = {}", p1); //Output: p1 = alice (24)
    println!("p1 = {}", p1.to_string()); //Output: p1 = alice (24)
}

std::fmt::Display トレイトを実装すると ToString トレイトもセットで実装される。 便利!

std::fmt::Debug トレイトの実装はもっと簡単で, derive 構文を使って

#[derive(Debug)]
struct Person {
    age: u32,
    name: String,
}

fn main() {
    let p1 = Person {
        age: 24,
        name: "alice".to_string(),
    };
    println!("p1 = {:?}", p1); //Output: p1 = Person { age: 24, name: "alice" }
}

とすればよい。

ちなみに全ての組み込み型と標準ライブラリで定義される型は std::fmt::Debug トレイトを実装済みなので,さきほど to_string() メソッドが使えないと書いたタプルや配列でも

fn main() {
    println!("{:?}", (123, 1.13)); //Output: (123, 1.13)
    println!("{:?}", [1, 2, 3]); //Output: [1, 2, 3]
}

のようにできる。

文字列から他の型の値を取得する

std::str::FromStr トレイトを実装している型であれば文字列からその型の値を取得できる。

pub trait FromStr: Sized {
    type Err;
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

整数や浮動小数点数などの基本型は std::str::FromStr トレイトを実装している。 返り値は Result 型なので何らかのエラーハンドリングが必要だが,以下のコードでは端折っている1

use std::str::FromStr;

fn main() {
    println!("{:?}", i64::from_str("123")); //Output: Ok(123)
    println!("{:?}", f64::from_str("1.23")); //Output: Ok(1.23)
    println!("{:?}", bool::from_str("true")); //Output: Ok(true)
}

ちなみに大文字の "TRUE" はダメらしい(笑)

use std::str::FromStr;

fn main() {
    println!("{:?}", bool::from_str("TRUE")); //Output: Err(ParseBoolError { _priv: () })
}

小文字に変換すればいいかな。

use std::str::FromStr;

fn main() {
    println!("{:?}", bool::from_str(&"TRUE".to_lowercase())); //Output: Ok(true)
}

文字列に対して parse() メソッドを使う方法もある。 parse() メソッド内部で from_str() を呼び出しているらしい。

fn main() {
    println!("{:?}", "123".parse::<i64>()); //Output: Ok(123)
    println!("{:?}", "TRUE".to_lowercase().parse::<bool>()); //Output: Ok(true)
}

記述としてはどっちもどっちだな。

参考図書

photo
プログラミング言語Rust 公式ガイド
Steve Klabnik (著), Carol Nichols (著), 尾崎 亮太 (翻訳)
KADOKAWA 2019-06-28 (Release 2019-06-28)
単行本
4048930702 (ASIN), 9784048930703 (EAN), 4048930702 (ISBN)
評価     

公式ドキュメントの日本語版。索引がちゃんとしているので,紙の本を買っておいて手元に置いておくのが吉。

reviewed by Spiegel on 2020-02-24 (powered by PA-APIv5)

photo
プログラミングRust
Jim Blandy (著), Jason Orendorff (著), 中田 秀基 (翻訳)
オライリージャパン 2018-08-10
単行本(ソフトカバー)
4873118557 (ASIN), 9784873118550 (EAN), 4873118557 (ISBN)
評価     

Eブック版あり。公式ドキュメントよりも系統的に書かれているので痒いところに手が届く感じ。ただし量が多いので,一度斜め読みしたらあとは傍らに置いて必要に応じてつまみ食いしていくのがいいだろう。

reviewed by Spiegel on 2020-03-08 (powered by PA-APIv5)


  1. エラー・ハンドリングについては「エラー・ハンドリングのキホン」を参考にどうぞ。 ↩︎