← [ BACK_TO_NOTES ]

Rust 错误处理

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

#concept #growing #dev #rust

[!info] related notes

Rust 错误处理

这个概念为什么出现

失败分两类:

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

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

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

最小可运行示例

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

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

use std::fs;
use std::io::ErrorKind;

// 业务意图:读取端口;缺省 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(e) if e.kind() == ErrorKind::NotFound => return Ok(8080),
        Err(e) => return Err(format!("read port config {path}: {e}")),
    };
    text.trim()
        .parse::<u16>()
        .map_err(|e| format!("invalid port in {path}: {e}"))
}

fn main() -> Result<(), String> {
    let path = std::env::args().nth(1).unwrap_or_else(|| "app.port".into());
    let port = read_port(&path)?;
    println!("configured_port={port}");
    Ok(())
}

建议在未创建 app.port 的示例项目中运行 cargo run,应使用默认值;也可 cargo run -- /path/to/app.port 指定配置文件。文件内容为 3000 时打印 configured_port=3000,内容非数字时返回错误与非零退出状态。

默认文件不存在时的期望输出:

configured_port=8080

只把 NotFound 视为缺省,权限错误、目录读取、非法 UTF-8 等都向上返回,不能静默改为 8080。此示例仅解析配置,没有实际监听;u16 允许 0,如应用不接受系统自动分配端口,应另加范围校验。String 错误用于短例子,公共库应保留类型化原因。

结合场景再看三个关注点

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

核心概念与准确模型

Result 传播

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

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

panic

  • panic! / unwrap / 数组越界等
  • 用于“程序员错误”
  • catch_unwind 只能捕获 unwind panic,捕获不了 panic=abort 或进程终止;panic hook 仍先运行,不能当常规输入错误处理或完整故障隔离

错误类型策略

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

设计动机

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

边界与误区

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

[!warning] 常见误区:所有失败都 panic 用户输入、网络失败应作为可处理的 Result 交给边界决策;某些失败仍需要退出,Result 本身不会自动重试。

工程实践

  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/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本