Skip to content

错误处理

可恢复错误用 Result<T, E>Ok(T)Err(E)? 在出错时提前返回 Err,成功则解开 Ok。函数返回 Result 才能用 ?

rust
use std::fs;
use std::io;

fn read_config(path: &str) -> Result<String, io::Error> {
    let text = fs::read_to_string(path)?;
    Ok(text)
}

? 会尝试 From 转换错误类型,因此内部错误只要实现了 From<底层错误> 就能向上收口。

panic

panic!unwrapexpect、断言失败会终止当前线程。它们表示程序 bug 或不可继续的不变量破坏,不是业务失败的默认路径。

库里对用户输入、I/O、网络不要 unwrap。二进制的 main 可以返回 Result,让运行时打印错误并以非零状态退出:

rust
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let text = read_config("config.toml")?;
    println!("{text}");
    Ok(())
}

库与应用

库定义自己的错误类型,保留足够上下文,避免过早抹成字符串。常用 thiserror 派生 DisplayFrom

rust
use thiserror::Error;

#[derive(Debug, Error)]
pub enum ConfigError {
    #[error("read config failed")]
    Io(#[from] std::io::Error),
    #[error("invalid syntax: {0}")]
    Parse(String),
}

应用侧(二进制、服务入口)可以用 anyhow::Result<T> 做类型擦除,方便组合多种错误并附加上下文:

rust
use anyhow::{Context, Result};

fn load() -> Result<String> {
    std::fs::read_to_string("config.toml").context("read config.toml")
}

thiserror 面向对外 API 的错误形状,anyhow 面向应用内部的传播。两者方向相反,不要在库的公开签名里返回 anyhow::Error

基于 MIT 许可发布