7.2 使用 Result 进行可恢复错误处理

Rust 将大多数运行时错误视为可恢复的,即程序在出错后仍有机会继续执行或优雅降级。为此,标准库提供了 Result<T, E> 枚举类型,作为表达操作成功或失败的标准方式。

Result 的定义与基本用法

Result 定义如下:

enum Result<T, E> {
    Ok(T),
    Err(E),
}
  • Ok(T) 包含成功时的结果值;
  • Err(E) 包含错误信息,通常是一个实现了 std::error::Error trait 的类型。

例如,尝试打开一个文件:

use std::fs::File;

let f = File::open("hello.txt");

File::open 返回 Result<File, std::io::Error>。如果文件存在且可读,返回 Ok(file);否则返回 Err(error)

使用 match 处理 Result

最直接的方式是使用 matchResult 进行模式匹配:

match f {
    Ok(file) => {
        println!("File opened successfully");
        // 使用 file
    }
    Err(error) => {
        println!("Failed to open file: {}", error);
    }
}

这种写法显式、安全,并强制处理两种可能结果。

组合器方法简化处理

除了 matchResult 提供了多种组合器方法,适用于链式操作:

  • unwrap():若为 Ok,返回内部值;若为 Err,则 panic(仅用于原型或确定不会失败的场景)。
  • expect(msg):类似 unwrap,但可自定义 panic 信息。
  • unwrap_or(default):失败时返回默认值。
  • map(f):若成功,对值应用函数 f;否则保持 Err
  • and_then(f):若成功,调用 f(返回另一个 Result),实现链式错误传播。

示例:

let content = File::open("data.txt")
    .and_then(|f| std::io::read_to_string(f))
    .unwrap_or_else(|e| {
        eprintln!("Error reading file: {}", e);
        String::new()
    });

错误类型的选择

标准库中常见的错误类型包括:

  • std::io::Error:I/O 操作错误;
  • std::num::ParseIntError:整数解析失败;
  • std::string::FromUtf8Error:UTF-8 解码错误。

这些类型都实现了 std::error::Error trait,支持统一处理和格式化输出。

为什么 Result 更安全

与异常或返回错误码不同,Result 将错误编码在类型系统中:

  • 编译器强制你处理或显式忽略错误;
  • 不会因忘记检查而跳过错误;
  • 错误值携带上下文信息,便于诊断。

小结

Result<T, E> 是 Rust 处理可恢复错误的核心机制。通过模式匹配或组合器方法,开发者可以清晰、安全地表达“成功路径”和“失败路径”。它鼓励显式错误处理,避免隐藏的失败逻辑,是构建可靠系统的基础。在后续章节中,我们将学习如何通过 ? 操作符进一步简化错误传播,以及如何定义自己的错误类型以提升代码的可维护性。

#Rust 入门教程 分享于 1 周前

内容由 AI 创作和分享,仅供参考