キャスト
Rust はプリミティブ型の間で暗黙的な型変換(型強制)を提供しません。 ただし、as キーワードを使うことで明示的な型変換(キャスト)を行えます。
整数型の間の変換ルールは、一般に C の慣習に従います。 ただし、C で未定義動作となる場合は例外です。Rust では、整数型間のすべてのキャストの動作が明確に定義されています。
// オーバーフローするキャストによるすべてのエラーを抑制する。 #![allow(overflowing_literals)] fn main() { let decimal = 65.4321_f32; // エラー!暗黙的な変換はない let integer: u8 = decimal; // FIXME ^ この行をコメントアウトする // 明示的な変換 let integer = decimal as u8; let character = integer as char; // エラー!変換ルールには制限がある。 // 浮動小数点数は char に直接変換できない。 let character = decimal as char; // FIXME ^ この行をコメントアウトする println!("Casting: {} -> {} -> {}", decimal, integer, character); // 任意の値を符号なし型 T にキャストするとき、 // 上記のように #![allow(overflowing_literals)] lint が指定されている場合に限り、 // 値が新しい型に収まるまで T::MAX + 1 が加算または減算される。 // そうでない場合はコンパイラエラーになる。 // 1000 はすでに u16 に収まる println!("1000 as a u16 is: {}", 1000 as u16); // 1000 - 256 - 256 - 256 = 232 // 内部的には、最下位ビット(LSB)側の最初の 8 ビットが保持され、 // 最上位ビット(MSB)側に向かう残りのビットは切り捨てられる。 println!("1000 as a u8 is : {}", 1000 as u8); // -1 + 256 = 255 println!(" -1 as a u8 is : {}", (-1i8) as u8); // 正の数の場合、これは剰余と同じ println!("1000 mod 256 is : {}", 1000 % 256); // 符号付き型にキャストするとき、(ビット単位の)結果は、 // まず対応する符号なし型にキャストした場合と同じになる。 // その値の最上位ビットが 1 なら、その値は負になる。 // もちろん、すでに収まっている場合は別。 println!(" 128 as a i16 is: {}", 128 as i16); // 境界ケースでは、8 ビットの 2 の補数表現における値 128 は -128 になる println!(" 128 as a i8 is : {}", 128 as i8); // 上の例を繰り返す // 1000 as u8 -> 232 println!("1000 as a u8 is : {}", 1000 as u8); // そして、8 ビットの 2 の補数表現における 232 の値は -24 になる println!(" 232 as a i8 is : {}", 232 as i8); // Rust 1.45 以降、浮動小数点数から整数へキャストするとき、 // `as` キーワードは *飽和キャスト* を行う。 // 浮動小数点値が上限を超えるか下限未満の場合、 // 返される値は超えた境界値と等しくなる。 // 300.0 as u8 は 255 println!(" 300.0 as u8 is : {}", 300.0_f32 as u8); // -100.0 as u8 は 0 println!("-100.0 as u8 is : {}", -100.0_f32 as u8); // nan as u8 は 0 println!(" nan as u8 is : {}", f32::NAN as u8); // この動作にはわずかな実行時コストがかかるが、 // unsafe なメソッドを使えば回避できる。ただし、結果がオーバーフローして // **不健全な値** を返す可能性がある。これらのメソッドは慎重に使うこと: unsafe { // 300.0 as u8 は 44 println!(" 300.0 as u8 is : {}", 300.0_f32.to_int_unchecked::<u8>()); // -100.0 as u8 は 156 println!("-100.0 as u8 is : {}", (-100.0_f32).to_int_unchecked::<u8>()); // nan as u8 は 0 println!(" nan as u8 is : {}", f32::NAN.to_int_unchecked::<u8>()); } }