类型转换

Rust 不支持原始类型之间的隐式类型转换(强制转换)。但可以使用 as 关键字进行显式类型转换(转型)。

整数类型之间的转换规则通常遵循 C 语言惯例,但 C 中存在未定义行为的情况除外。在 Rust 中,所有整数类型之间的转换行为都有明确定义。

// 抑制所有由溢出转换引起的警告。
#![allow(overflowing_literals)]

fn main() {
    let decimal = 65.4321_f32;

    // 错误!不允许隐式转换
    let integer: u8 = decimal;
    // 修复:^ 注释掉此行

    // 显式转换
    let integer = decimal as u8;
    let character = integer as char;

    // 错误!转换规则有限制。
    // 浮点数不能直接转换为字符。
    let character = decimal as char;
    // 修复:^ 注释掉此行

    println!("类型转换:{} -> {} -> {}", decimal, integer, character);

    // 当将任何值转换为无符号类型 T 时,
    // 会反复加上或减去 T::MAX + 1,直到该值
    // 适合新类型

    // 1000 已经适合 u16
    println!("1000 转换为 u16 是:{}", 1000 as u16);

    // 1000 - 256 - 256 - 256 = 232
    // 实际上,保留了最低有效位(LSB)的前 8 位,
    // 而朝最高有效位(MSB)方向的其余位被截断。
    println!("1000 转换为 u8 是:{}", 1000 as u8);
    // -1 + 256 = 255
    println!("  -1 转换为 u8 是:{}", (-1i8) as u8);

    // 对于正数,这等同于取模运算
    println!("1000 对 256 取模是:{}", 1000 % 256);

    // 当转换为有符号类型时,(按位)结果等同于
    // 先转换为对应的无符号类型。如果该值的最高有效位
    // 为 1,则该值为负数。

    // 当然,如果已经适合的话就不需要转换。
    println!(" 128 转换为 i16 是:{}", 128 as i16);

    // 边界情况:128 在 8 位二进制补码表示中为 -128
    println!(" 128 转换为 i8 是:{}", 128 as i8);

    // 重复上面的例子
    // 1000 转换为 u8 -> 232
    println!("1000 转换为 u8 是:{}", 1000 as u8);
    // 而 232 在 8 位二进制补码表示中为 -24
    println!(" 232 转换为 i8 是:{}", 232 as i8);

    // 从 Rust 1.45 开始,`as` 关键字在浮点数转整数时执行*饱和转换*
    // 如果浮点值超出上界或低于下界,返回值
    // 将等于所越过的边界值。

    // 300.0 转换为 u8 是 255
    println!(" 300.0 转换为 u8 是:{}", 300.0_f32 as u8);
    // -100.0 转换为 u8 是 0
    println!("-100.0 转换为 u8 是:{}", -100.0_f32 as u8);
    // NaN 转换为 u8 是 0
    println!("   NaN 转换为 u8 是:{}", f32::NAN as u8);

    // 这种行为会产生少量运行时开销,可以通过不安全方法避免,
    // 但结果可能溢出并返回**不可靠的值**。请谨慎使用这些方法:
    unsafe {
        // 300.0 转换为 u8 是 44
        println!(" 300.0 转换为 u8 是:{}", 300.0_f32.to_int_unchecked::<u8>());
        // -100.0 转换为 u8 是 156
        println!("-100.0 转换为 u8 是:{}", (-100.0_f32).to_int_unchecked::<u8>());
        // NaN 转换为 u8 是 0
        println!("   NaN 转换为 u8 是:{}", f32::NAN.to_int_unchecked::<u8>());
    }
}