讲解
标量类型表示单个值,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)。记住三条纪律:溢出要显式、转换要显式、浮点比较用误差。下一章看复合类型:元组与数组。