2.1 类型系统:物证清单


2.1 类型系统:物证清单

本节摘要:清点 Rust 的标量类型与复合类型,重点演示两个高频初审案件——E0308 类型不匹配与整数溢出处理。读完你能根据取值范围选对整数类型,并明白为什么 Rust 拒绝一切隐式转换。

标量类型四类

类别 类型 备注
整数 i8..i128、u8..u128、isize、usize i 有符号,u 无符号,默认推断为 i32
浮点 f32、f64 默认 f64
布尔 bool 只有 true 与 false 两个字面量
字符 char 四字节 Unicode 标量,能存汉字与 emoji

复合类型两种:元组(定长异构)与数组(定长同构)。定长是关键判据——长度写进类型,越界在编译期或运行期都有防线:

let evidence: (u32, &str, bool) = (173, "卷宗", true); let (no, title, _) = evidence; // 解构,下划线弃权 let samples: [u8; 3] = [7, 9, 2]; let first = samples[0];

初审案件两则

案件一:隐式转换,驳回。 把 i32 直接交给 u8 参数:

fn weigh(mass: u8) -> u32 { mass as u32 } let total = weigh(300);

300 超出 u8 上限,编译器直接报"字面量超出 u8 范围"。若两变量类型不同,如 i32 加 u32,得到 E0308,必须显式 as 转换。这条法规减少的隐患是隐式的截断与符号扩展错误——它们在 C 里是事故常客。

案件二:溢出,看模式。 debug 构建下整数溢出直接 panic(运行期兜底);release 构建回绕。需要明确语义时用标准库的检查方法:

let sum = 250u8.checked_add(10); // None,不崩溃 let wrap = 250u8.wrapping_add(10); // 4,明确要回绕

图:整数类型选型速查

图:整数类型选型速查

要点回顾

  • 默认整数 i32、浮点 f64,不写类型时的推断结果;
  • 没有隐式数值转换,跨类型运算必须显式 as 或 From;
  • 元组与数组都定长,可变长度交给第 4 章的 Vec;
  • 溢出行为分构建模式,敏感运算用 checked 系列方法。

💡 关键直觉:类型标注是免费的文档——fn transfer(amount: u64) 比"传个数字"传达的多得多。

类型推断的边界在哪

Rust 的推断比表面看起来克制:它是局部的、单向的,不做全程序分析。函数签名是推断的墙——参数与返回类型必须显式,函数体内的推断不越过这道墙。这条设计让公开 API 永远自文档化。

fn weigh(items: &[u32]) -> u64 { // 签名显式,公开承诺 let total = items.iter().sum(); // 推断依据签名:u64 total } fn main() { let x = 100; // 默认 i32 let y = 100u8; // 后缀改判为 u8 let z: u16 = x as u16 + y as u16; // as 是显式改判,程序员担责 println!("{} {}", weigh(&[z as u32]), y); }

as 转换要当作"放弃检查的改判"看待:300u16 as u8 得 44,截断无声发生。涉及可能越界的场景,标准库给了三条更负责的路径,语义各不相同。

写法 越界时行为 适用场景
as 截断,无提示 位级 reinterpret,确知范围
try_into 返回 Err 不可信输入的边界换算
clamp 收敛到边界 物理量限幅

溢出在两套档案下判罚不同

整型溢出是最容易被忽略的方言差异:debug 构建里溢出触发 panic(当作程序错误当庭扣留),release 构建里则回绕(当作性能优先)。若想两套档案下判罚一致,显式说出意图。

fn accrue(base: u32, delta: u32) -> u32 { base.checked_add(delta) // 明示:越界是可预期案件 .expect("计数值不应溢出") // 越界即 panic,两种构建一致 } fn wrap_clock(base: u32, delta: u32) -> u32 { base.wrapping_add(delta) // 明示:回绕是业务语义 }

checked_*wrapping_*saturating_* 三族方法把溢出策略写进代码,审查者一眼可辨。把"隐式 as 加默认溢出"改成"显式策略方法",是初学者到工程师的分水岭之一。

标量清单与物证编号

类型 宽度 备注
i8–i128 / u8–u128 8–128 位 字面量默认 i32
f32 / f64 32 / 64 位 f32 精度 6–7 位十进制
bool / char 1 字节 / 4 字节 char 是 Unicode 标量值
usize / isize 平台指针宽 索引与长度专用

usize 专门留给索引与长度,数组下标用它是因为它天然与内存地址同宽——用 i32 当索引反而要回答"负下标什么语义"这个多余问题。char 是 4 字节而非 1 字节,这点与 C 的经验相左,中文字符串的处理在第 4 章集合一节还会开庭。

推断失败时的法定补救

推断偶尔会卡死,典型现场是空容器与 collect:let v = Vec::new(); 时编译器无法知道元素类型,E0282(type annotations needed)出庭。补救按侵入性从低到高排:变量处标注 let v: Vec<u32> = Vec::new();;字面量后缀 0u32;turbofish Vec::<u32>::new();函数边界显式签名。优先选前两种,turbofish 留给链式调用末端的 collect 这种别无选择的位置。见到 E0282 不必慌,它只是在说"信息不够,你补一处即可",通常一行解决。

整型选型的工程惯例

用途 首选 理由
数量、计数、长度 usize 天然配索引与容量
文件大小、协议字段 u32 / u64 按协议定宽,跨平台一致
差值、方向 i32 / i64 可能出现负值
抽象但非负的编号 u32 语义自说明

i32 默认是刻意的:它对绝大多数平台都是最快宽度之一,且留了符号余量。推翻默认要有理由,"编号不会是负数"就够给编号上 u32;而把循环下标从 i32 改 usize 是迁移到真实项目时最常见的机械修改之一。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U