Rust 错误处理

可恢复错误用 Result,不可恢复用 panic;? 传播、错误类型设计与库/二进制边界策略。

#type / concept #status / growing #tech / dev #resource / rust

[!info] 关联笔记

Rust 错误处理

这个概念为什么出现

失败分两类:

  1. 可恢复:文件不存在、校验失败、下游超时 → 调用方可能换路径
  2. 不可恢复:程序不变量被破坏 → 立刻停止比带病运行更安全

Rust 用 Result 服务第一类,用 panic 服务第二类。

[!abstract] 一句话理解 可恢复错误返回 Result 并用 ? 传播;panic 留给 bug/不变量;库暴露类型化错误,二进制在边界决定日志与退出码。

最小可运行示例

场景:配置加载——缺文件可恢复,解析到非法端口则失败

服务启动读端口配置;缺文件给默认;端口非数字则返回错误,由 main 打印并退出语义。

use std::fs;
use std::num::ParseIntError;

// 业务意图:读取端口;缺省 8080;坏数据向上返回。
// 教学点:Result 传播;map_err 增加上下文;main 返回 Result。

fn read_port(path: &str) -> Result<u16, String> {
    let text = match fs::read_to_string(path) {
        Ok(t) => t,
        Err(_) => return Ok(8080), // 缺文件:可恢复默认
    };
    text.trim()
        .parse::<u16>()
        .map_err(|e: ParseIntError| format!("invalid port '{text}': {e}"))
}

fn main() -> Result<(), String> {
    // 演示:用内联解析代替真实文件,保证示例可运行
    let port: u16 = "3000".parse().map_err(|e| format!("{e}"))?;
    println!("listening_port={port}");
    let bad = read_port("/this/path/should/not/exist/app.port")?;
    println!("default_or_file_port={bad}");
    Ok(())
}

建议运行:cargo run

期望输出(示例):

listening_port=3000
default_or_file_port=8080

结合场景再看三个关注点

  1. 缺文件有默认是产品决策,用 Result 分支表达
  2. ?main 可简洁传播
  3. 上下文用 map_err/anyhow 上下文(生态)

核心概念与准确模型

Result 传播

let v = fallible()?; // 等价于 match 后 early return

? 需要返回类型兼容(From 转换错误类型)。

panic

  • panic! / unwrap / 数组越界等
  • 用于“程序员错误”
  • catch_unwind 但不是常规控制流

错误类型策略

场景常见选择
库公共 API自定义错误枚举 / thiserror
应用二进制anyhow::Error 等易用包装
细粒度匹配枚举变体 + source

设计动机

  • 失败可见
  • 零成本抽象下的显式控制流
  • 区分 bug 与业务失败

边界与误区

  • 不要用 panic 处理用户输入错误
  • 不要在库里到处 unwrap
  • 错误类型过大导致匹配痛苦

[!warning] 常见误区:所有失败都 panic 用户输入、网络抖动必须可恢复。

工程实践

  1. 库:类型化错误 + Display/Error trait
  2. 应用:边界记录日志、指标、退出码
  3. 保留 source 链便于排障
  4. 测试断言错误变体而不只是 is_err

本节总结

  • Result vs panic
  • ? 传播
  • 库/应用错误策略分层

自测题

  1. 用户输入非法邮箱该 Result 还是 panic?
  2. 为什么库不宜只返回 String 错误?
参考答案
  1. Result。
  2. 调用方难以稳定匹配与包装,也难做 i18n/结构化。

延伸阅读与资料来源

资料类型支撑内容
The Book — Error Handling官方书错误处理
std::error::Error标准库Error trait
anyhow / thiserror生态应用/库错误
创建于 2026/7/15 更新于 2026/7/15