外观
雷区 2:main 里想用 ?,编译器不同意
症状
rust
use std::fs;
fn main() {
let content = fs::read_to_string("不存在.txt")?;
println!("{}", content);
}编译输出
text
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option`
(or another type that implements `FromResidual`)
--> src/main.rs:4:49
|
4 | let content = fs::read_to_string("不存在.txt")?;
| ^ cannot use the `?` operator in a function that returns `()`诊断
第 8 章讲过 ? 的规矩:只能用在返回 Result(或 Option)的函数里——? 失败时要"带着错误回家",家里得有 Result 的门让它进门。而 main 的默认返回类型是 (),没有门,? 进不去。
所以新手经常在 main 里写 ? 碰壁。好消息:这个雷区有官方解药——让 main 自己返回 Result。
解药
解药一:让 main 返回 Result<(), 错误类型>——? 到处用,错误自动传给系统:
rust
use std::fs;
fn main() -> Result<(), String> {
let content = fs::read_to_string("不存在.txt").map_err(|e| format!("读文件失败:{}", e))?;
println!("{}", content);
Ok(())
}main 返回 Err 时,程序以退出码 1 结束,错误消息打印到终端——行为清晰,代码干净。
解药二:用 anyhow 的 Result<()>(真实项目首选,错误处理篇雷区 7 详解):
rust
use anyhow::{Context, Result};
fn main() -> Result<()> {
let content = fs::read_to_string("不存在.txt").context("读取文件失败")?;
println!("{}", content);
Ok(())
}解药三:main 保持 (),错误自己接住——不想改返回类型时:
rust
fn main() {
if let Err(message) = run() {
eprintln!("程序出错:{}", message);
std::process::exit(1);
}
}
fn run() -> Result<(), String> {
// 这里可以随便用 ?
let content = std::fs::read_to_string("不存在.txt").map_err(|e| e.to_string())?;
println!("{}", content);
Ok(())
}这是第 13 章故事搜索器的写法:业务逻辑全在 run() 里用 ?,main 只负责接住错误、决定怎么退出。
预防
- 报错关键词:
cannot use the ? operator in a function that returns ()——你的函数返回类型不对,不是?坏了 - 三个选择:main 返回
Result(最简单)、包一层run()(最灵活)、anyhow(最省心) main -> Result<(), E>的 E 要统一:多个?的错误类型必须能互相转换(这就是为什么真实项目用anyhow::Error——什么错误都能收)