外观
雷区 3:错误被悄悄吞掉,程序带病运行
症状
rust
use std::fs;
fn main() {
let _ = fs::read_to_string("配置.txt");
// ……继续假设配置存在,继续干活……
println!("程序照常运行!");
}编译通过,运行"正常"——没有任何报错。但 read_to_string 可能已经失败了(文件不存在),错误被 let _ = 无声无息地丢掉。
诊断
let _ = 可能出错的操作; 是错误处理里最隐蔽的坑:它把 Result 整个扔掉,失败和成功看起来一模一样。程序继续跑,但"配置"其实没加载成功——于是后面出现一系列莫名其妙的问题:配置是空的、行为不对、数据丢失……真正的 bug 早就发生了,你却在错误的地方找半天。
被吞掉的错误还有这些姿势:
rust
let _ = fs::remove_file("temp.txt"); // 删失败?无所谓?
let _ = stream.write_all(&data); // 写失败?数据悄悄丢!
let _ = sender.send(message); // 发送失败?接收方永远等不到!凡是"可能出错"的调用,let _ = 都是把错误埋进土里。 AGENTS 里有句话:静默吞掉一个显式报告的错误,比崩溃更糟——因为崩溃会告诉你,吞错不会。
解药
解药一:至少看一眼(if let Err)——"失败了就喊一声,成功了才继续":
rust
use std::fs;
fn main() {
let config = match fs::read_to_string("配置.txt") {
Ok(content) => content,
Err(error) => {
println!("警告:配置读取失败,使用默认配置。原因:{}", error);
String::from("默认配置")
}
};
println!("配置:{}", config);
}解药二:该报错就报错(?)——失败不是"无所谓",而是"要停止":
rust
use std::fs;
fn main() -> Result<(), String> {
let config =
fs::read_to_string("配置.txt").map_err(|e| format!("读取配置失败:{}", e))?;
println!("配置:{}", config);
Ok(())
}解药三:真的"删不掉也无所谓"?也要白纸黑字写出来——用 let _ = 前,加一句注释说明"这里失败是有意的":
rust
// 临时文件删不掉没关系,系统会清理
let _ = fs::remove_file("temp.txt");预防
- 看到
let _ =出现在Result/Option上,先问:这个失败真的可以无视吗?可以 → 加注释;不可以 → match 或? - 纪律:错误要么处理、要么传播、要么白纸黑字地忽略——三选一,不许"假装没看见"
- clippy 会报警:
let_underscore_must_use等 lint 专门抓这种吞错,cargo clippy定期跑 - 写测试时格外注意:测试里的
let _ =吞掉错误,会导致"测试全绿但功能全坏"的幻觉