Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

キャスト

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>());
    }
}