Rustの型変換
Rustは、ある型を別の型へ自動で変換してはくれません。同じ式の中で i32 と f64 を混ぜると、コンパイルが通らないのです。変換は自分ではっきり書く必要があります。これはわざとそうなっています。ほかの言語では、気づかないうちに行われる型変換がバグのよくある原因になっているからです。
as で数値型を変換する
Section titled “as で数値型を変換する”ある数値型を別の数値型にキャスト(変換)するには、as キーワードを使います。
fn main() { let x: i32 = 10; let y: f64 = x as f64; // i32 -> f64
println!("{y}");}これは見た目以上に大切です。キャストせずに整数どうしで割り算をすると、おそらく期待していた小数の結果ではなく、整数の割り算になってしまいます。
fn main() { let a = 10; let b = 3;
println!("{}", a / b); // 3(整数の割り算) println!("{}", a as f64 / b as f64); // 3.3333333333333335}小さい型へのキャストではデータが失われることがある
Section titled “小さい型へのキャストではデータが失われることがある”大きい型から小さい型へキャストしても(たとえば i32 から u8)、エラーにはなりません。収まらない部分が切り捨てられるだけです。そのため、びっくりするような結果になることがあります。
fn main() { let big: i32 = 300; let small = big as u8; // u8 には 0〜255 しか入らない println!("{small}"); // 300 ではなく 44。一周して戻ってしまった}浮動小数点数・文字・真偽値のキャスト
Section titled “浮動小数点数・文字・真偽値のキャスト”as は整数以外の型にも使えます。それぞれに知っておきたいルールがあります。
fn main() { println!("{}", 3.99_f64 as i32); // 3:小数点以下は切り捨て println!("{}", -3.99_f64 as i32); // -3:小さいほうではなく、0の方向に切り捨て println!("{}", 3.99_f64.round() as i32); // 4:四捨五入したいなら先に round する println!("{}", 300.0_f64 as u8); // 255:大きすぎるので最大値で止まる println!("{}", -5.0_f64 as u8); // 0:小さすぎるので最小値で止まる println!("{}", 'A' as u32); // 65:文字のコード番号 println!("{}", 97_u8 as char); // a:逆向きの変換 println!("{}", true as i32); // 1(false なら 0)}実行結果:
3-34255065a1ここで覚えておきたいポイントは次のとおりです。
- 浮動小数点数から整数への変換では、小数点以下がすべて捨てられます。四捨五入はされません。いちばん近い整数にしたいなら、先に
.round()を呼びましょう。 - 範囲外の浮動小数点数は、収まるいちばん近い値に丸め込まれます(
u8では300.0が255になります)。一周して戻る整数とは違います(上の例では300が44になりました)。 - 文字の裏には番号(Unicodeのコードポイント)があります。
'A' as u32は65になります。charにそのままキャストし直せるのはu8だけです。もっと大きな数にはchar::from_u32を使います。すべての数が有効な文字になるわけではないからです。 - 真偽値は
1か0になります。逆向きはできません。1 as boolはコンパイルが通らないので、代わりにn != 0のような比較を使いましょう。
文字列を数値に変換する(パース)
Section titled “文字列を数値に変換する(パース)”as によるキャストは、数値型どうしでしか使えません。テキストを数値に変換したいとき、たとえばユーザーが入力したものを数値にしたいときは、.parse() を使います。
fn main() { let text = "42"; let number: i32 = text.parse().expect("有効な数値ではありません");
println!("{}", number + 8);}実行結果:
50.parse() は失敗することがあります(テキストがそもそも数値でなかったら?)。そのため、数値を直接返すのではなく Result を返します。Result はまだ説明していませんが、今のところは .expect("メッセージ") を「失敗したら、このメッセージを出してプログラムを止める」という簡単な書き方だと思っておいてください。きちんとした扱い方は Result のページで紹介します。
数値を文字列に変換する
Section titled “数値を文字列に変換する”逆方向の変換はもっと簡単です。ほとんどの型は、.to_string() で String に変換できます。
fn main() { let number = 42; let text = number.to_string(); println!("{}", text + "!");}1. 平均点
Section titled “1. 平均点”3回のテストの点数 7、8、10 を i32 の値として保存してください。合計を表示し、続けて平均を小数点以下2桁で表示します。ヒント:整数どうしで割ると 8.33 ではなく 8 になってしまうので、先に合計を f64 にキャストしましょう。{:.2} で小数点以下2桁を表示できます。
解答を見る
fn main() { let a: i32 = 7; let b: i32 = 8; let c: i32 = 10;
let sum = a + b + c; let average = sum as f64 / 3.0; // 25 / 3 ではなく 25.0 / 3.0
println!("合計: {sum}"); println!("平均: {:.2}", average);}実行結果:
合計: 25平均: 8.332. テキストから価格を求める
Section titled “2. テキストから価格を求める”お店から、価格がテキストの "4.50" で、個数が i32 の 3 で渡されました。テキストを f64 に変換して個数を掛け、合計: 13.5 と表示してください。ヒント:このページの2つの道具を両方使います。テキストには .parse()、個数には as f64 です。
解答を見る
fn main() { let price_text = "4.50"; let quantity: i32 = 3;
let price: f64 = price_text.parse().expect("有効な価格ではありません"); let total = price * quantity as f64; // f64 * f64
println!("合計: {total}");}実行結果:
合計: 13.5as f64 がなければ、Rustは f64 と i32 の掛け算を拒否します。Rustは、異なる数値型を勝手に混ぜることは決してしないからです。
- Rustは型を自動で変換しません。変換するときは、いつも明示的にキャストします。
- 数値型どうしの変換には
asを使います(x as f64、x as u8)。 - 小さい型へのキャストは、黙って切り捨てられます。エラーにならないので注意しましょう。
- 浮動小数点数から整数への変換では小数点以下が切り捨てられます(四捨五入するなら先に
.round())。charとboolも数値にキャストできます。 - テキストを数値にするには
.parse()、その逆には.to_string()を使います。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. Rustでキャストせずに 10 / 3 のように整数どうしを割ると、どうなりますか?
2. 300_i32 を as u8 でキャストすると、どうなりますか?
3. 文字列を数値に変換するとき、変換は失敗する可能性があるため、.parse() は何を返しますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- 型キャスト — Rust by Example 日本語版:
asによるたくさんのキャストを、それぞれ何になるかのコメント付きで実行できます。 - Type cast expressions — The Rust Reference(英語):どのキャストが許されているかの完全な表と、それぞれの正確なルールです。
- Stringとの型変換 — Rust by Example 日本語版:
.to_string()と.parse()を、もう少しくわしく説明しています。 TryFrom— 標準ライブラリのドキュメント(英語):値が収まらないかもしれないときに使う、チェック付きの変換(u8::try_from(...))です。- Numeric Types — The Rust Reference(英語):すべての整数型と浮動小数点数型のサイズと範囲です。