讲解

标量类型表示单个值,Rust 有四类:整数、浮点数、布尔值、字符。整数按位数和有符号性细分:i8/i16/i32/i64/i128(有符号)和 u8/u16/u32/u64/u128(无符号),外加 isize/usize(随平台指针宽度,多用于索引和长度)。不写标注时整数字面量默认推断为 i32——不确定用哪个就用 i32,性能在现代 CPU 上通常也是最好的。

整数溢出是必须要知道的行为差异:开发模式(debug)下溢出会 panic 直接崩溃,发布模式(release)下默认静默回绕(wrapping,256 进位的 u8 加 1 变成 0)。两种行为都不是「报错提示」,想要明确语义请用 checked_add(溢出返回 None)、wrapping_add(明确回绕)、saturating_add(停在边界)这些显式方法。

浮点是 f32 和 f64,默认 f64(精度更高,现代 CPU 上速度几乎一样),遵循 IEEE 754,所以 0.1 + 0.2 不等于 0.3 的老问题同样存在。布尔 bool 只有 true/false 两个值,且不会像 C 那样与整数互相隐式转换。字符 char 占 4 字节,表示一个 Unicode 标量值——'中'、'🦀' 都是合法的 char,这也意味着「第几个字符」不是 O(1) 操作,字符串章节会展开。

示例

四类标量与类型标注、字面量写法:

fn main() {
    let a: i32 = -42; // 显式标注
    let b = 42u64; // 字面量后缀标类型
    let million = 1_000_000; // 下划线只是可读性
    let pi: f64 = 3.14159;
    let active: bool = true;
    let crab: char = '🦀';

    println!("{a} {b} {million} {pi} {active} {crab}");

    assert_eq!(std::mem::size_of::<char>(), 4);
    assert_eq!(million, 1000000);
}

类型转换必须显式:as 做数值转换,parse 从字符串解析(失败会得到一个 Result,第 15 章细讲,这里先 unwrap):

fn main() {
    let x = 3.99_f64;
    let truncated = x as i32; // 截断,不是四舍五入
    assert_eq!(truncated, 3);

    let text = "1024";
    let n: i32 = text.parse().unwrap();
    assert_eq!(n, 1024);

    // 浮点比较用误差范围,不要用 ==
    let diff: f64 = 0.1 + 0.2 - 0.3;
    assert!(diff.abs() < 1e-10);
    println!("转换与比较都符合预期");
}

常见坑

  • 溢出在 release 才爆:debug 下溢出立刻 panic 反而安全;release 静默回绕会制造隐蔽 bug。金额、计数这类场景用 checked_* 系列方法。
  • 整数除零:1 / 0 直接 panic(浮点 1.0 / 0.0 得到 inf,不 panic),两者行为不同,别记混。
  • as 转换悄悄截断:大数转小类型、负数转无符号都不会报错,值直接变形;需要校验用 i32::try_from(x),失败能拿到错误。
  • 对浮点用 ==:0.1 + 0.2 == 0.3 是 false。比较浮点用差的绝对值小于一个 epsilon。

小结

四类标量:整数(默认 i32)、浮点(默认 f64)、bool、char(4 字节 Unicode)。记住三条纪律:溢出要显式、转换要显式、浮点比较用误差。下一章看复合类型:元组与数组。