Skip to content

错误处理概述

> 理解 Rust 的错误处理哲学,掌握 Result 和 Option 类型的基本用法,对比其他语言的错误处理机制。

为什么错误处理很重要?

概念名称: Rust 使用 Result<T, E>Option<T> 类型将错误作为值处理,而非异常。

语法结构:
┌──────────────────────────────────────┐
│  enum Result<T, E> {                 │
│      Ok(T),      // 成功,包含值      │
│      Err(E),     // 失败,包含错误    │
│  }                                   │
│                                       │
│  enum Option<T> {                    │
│      Some(T),    // 有值             │
│      None,       // 无值             │
│  }                                   │
│                                       │
│  处理模式:                            │
│  match result {                      │
│      Ok(v) => ...                    │
│      Err(e) => ...                   │
│  }                                   │
└──────────────────────────────────────┘

最简示例

rust
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err("除数不能为零".to_string())
    } else {
        Ok(a / b)
    }
}

fn main() {
    match divide(10.0, 2.0) {
        Ok(result) => println!("结果:{}", result),
        Err(e) => println!("错误:{}", e),
    }
}
▶ Run

现实世界的程序总会出错

rust
// 可能失败的操作
std::fs::File::open("config.txt");    // 文件可能不存在
std::net::TcpStream::connect("localhost:8080");  // 服务器可能离线
"123".parse::<i32>();                  // 字符串可能不是有效数字
vec![1, 2, 3][10];                     // 索引可能越界
▶ Run

错误处理的目标

┌─────────────────────────────────────────────────────┐
│              良好的错误处理                          │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 程序健壮性                                       │
│     • 遇到错误时不会崩溃                            │
│     • 能够优雅地降级或恢复                          │
│                                                     │
│  2. 用户友好                                        │
│     • 提供清晰的错误信息                            │
│     • 指导用户如何解决问题                          │
│                                                     │
│  3. 易于调试                                        │
│     • 记录足够的上下文信息                          │
│     • 追踪错误来源                                  │
│                                                     │
│  4. 类型安全                                        │
│     • 编译器强制处理错误                           │
│     • 不会遗漏错误情况                              │
│                                                     │
└─────────────────────────────────────────────────────┘

为什么用它?

rust
// 没有 Result:错误被忽略,程序崩溃
let file = std::fs::File::open("config.txt").unwrap();
// 如果文件不存在,直接 panic!

// 有 Result:错误被显式处理
match std::fs::File::open("config.txt") {
    Ok(file) => println!("文件打开成功"),
    Err(e) => println!("文件打开失败:{}", e),
}

// 使用 ? 操作符简化
fn read_config() -> Result<String, std::io::Error> {
    let content = std::fs::read_to_string("config.txt")?;
    Ok(content)
}
▶ Run

关键代码说明:

代码含义为什么这样写
Result<T, E>成功/失败的结果类型将错误作为值,强制调用者处理
Ok(T)成功分支包含有效值
Err(E)失败分支包含错误信息
? 操作符错误传播语法糖自动返回 Err,简化代码
.unwrap()提取值或 panic仅用于测试或确定不会失败时

小结

  • Rust 使用 Result<T, E>Option<T> 将错误作为值处理
  • 错误处理的目标:健壮性、用户友好、易于调试、类型安全
  • ? 操作符自动传播错误,大幅简化代码
  • 编译器强制处理错误,不会遗漏错误情况

练习题

详见:练习题