一个真实又眼熟的“坑”
在业务开发中,条件分支遗漏是一种高频且危害显著的缺陷模式。以下段 JavaScript 代码为例:
if (res === 200) {
console.log(200);
} else if (res === 300) {
console.log(300);
} else if (res === 400) {
console.log(400);
}
// ……后面没有 else 了
当接口返回 500、502 等新状态码时,流程会悄无声息地落入“无处理”路径,导致行为未定义。这类缺陷往往在测试阶段难以穷尽,最终触发线上故障。
Rust 的解决方案:穷尽性模式匹配,不写全就编译失败,没有“商量”二字
Rust 提供了 match 表达式,并通过编译期的穷尽性(exhaustiveness)检查,强制开发者覆盖所有可能情况:
enum HttpCode {
Ok, // 200
Redirect, // 300
BadRequest, // 400
}
fn handle(res: HttpCode) {
match res {
HttpCode::Ok => println!("200"),
HttpCode::Redirect => println!("3000"),
HttpCode::BadRequest => println!("4000"),
// 若后续新增 HttpCode::ServerError,此处将编译失败:
// error[E0004]: non-exhaustive patterns: `ServerError` not covered
}
}
编译器在代码生成前即可发现“遗漏分支”,把运行时风险转化为编译期错误,显著降低缺陷逃逸概率。
翻译成人话: “想偷懒?可以,先把编译器打服。”
在 Rust 的世界里, “漏分支”不是风格问题,是门都进不了的硬错误。
别的语言靠 Code Review 劝你善良;Rust 直接物理封印,不写全就寸步难行。
通配符?可以,但必须显式找骂
match code {
200 => {},
300 => {},
400 => {},
_ => { log::warn!("未知码,自行翻车"); },
}
你把 _ 通配符删掉试试?编译器立刻原地爆炸给你看。
落地建议:在现有工程中借力 Rust 思维
-
TypeScript 代码引入穷尽性检查
利用
never类型与联合类型,模拟 Rust 的穷尽性:type Code = 200 | 300 | 400 | 500; function handle(res: Code) { if (res === 200) { /* ... */ } else if (res === 300) { /* ... */ } else if (res === 400) { /* ... */ } else if (res === 500) { /* ... */ } else { const _exhaustive: never = res; // 新增枚举值时此处报错 } }需注意:必须开启
strictNullChecks等严格选项,并确保团队成员持续遵守。 -
Code Review 聚焦“可枚举类型”
将“条件分支是否完整”设为 PR 必检项,与自动化测试、静态分析结合,形成多层防护。