Skip to content

result option.rs

文件信息

  • 📄 原文件:01_result_option.rs
  • 🔤 语言:rust

完整代码

rust
// ============================================================
//                      错误处理
// ============================================================
// Rust 没有异常(exception),使用 Result<T, E> 和 Option<T> 处理错误
// 这是 Rust 可靠性的重要基石——编译器强制你处理所有可能的错误
//
// 两种错误:
// - 可恢复错误: Result<T, E>(如文件未找到、网络超时)
// - 不可恢复错误: panic!(如数组越界、断言失败)

use std::fs;
use std::io;
use std::num::ParseIntError;
use std::fmt;

fn main() {
    println!("=== 错误处理 ===");

    // ----------------------------------------------------------
    // 1. panic!(不可恢复错误)
    // ----------------------------------------------------------
    // 程序立即终止,打印错误信息和调用栈
    // 【适用场景】程序进入不可能恢复的状态
    // 【环境变量】RUST_BACKTRACE=1 显示完整调用栈

    // panic!("崩溃了!");  // 取消注释会终止程序

    // 数组越界也会 panic
    // let v = vec![1, 2, 3];
    // v[99];  // panic: index out of bounds

    // ----------------------------------------------------------
    // 2. Result<T, E> 基础
    // ----------------------------------------------------------
    println!("\n=== Result<T, E> ===");

    // 读取文件(可能失败)
    let result = fs::read_to_string("不存在的文件.txt");
    match result {
        Ok(content) => println!("文件内容: {}", content),
        Err(error) => println!("读取失败: {}", error),
    }

    // ----------------------------------------------------------
    // 3. ? 操作符(错误传播)
    // ----------------------------------------------------------
    // ? 是处理 Result 的语法糖:
    // - Ok(val) → 解包得到 val
    // - Err(e) → 提前返回 Err(e)
    //
    // 【重要】只能在返回 Result 或 Option 的函数中使用

    println!("\n=== ? 操作符 ===");

    match read_config("config.txt") {
        Ok(config) => println!("配置: {}", config),
        Err(e) => println!("读取配置失败: {}", e),
    }

    match parse_number("42") {
        Ok(n) => println!("解析成功: {}", n),
        Err(e) => println!("解析失败: {}", e),
    }

    match parse_number("abc") {
        Ok(n) => println!("解析成功: {}", n),
        Err(e) => println!("解析失败: {}", e),
    }

    // ----------------------------------------------------------
    // 4. Result 的常用方法
    // ----------------------------------------------------------
    println!("\n=== Result 方法 ===");

    let ok_val: Result<i32, String> = Ok(42);
    let err_val: Result<i32, String> = Err("错误".to_string());

    // unwrap / expect(有值返回,无值 panic)
    println!("unwrap: {}", ok_val.unwrap());
    // err_val.unwrap();  // panic!
    // err_val.expect("自定义 panic 信息");  // panic with message

    // unwrap_or / unwrap_or_else
    println!("unwrap_or: {}", err_val.unwrap_or(0));
    println!("unwrap_or_else: {}", err_val.unwrap_or_else(|_| 100));

    // map(转换 Ok 的值)
    let doubled = ok_val.map(|x| x * 2);
    println!("map: {:?}", doubled); // Ok(84)

    // map_err(转换 Err 的值)
    let mapped_err = err_val.map_err(|e| format!("包装: {}", e));
    println!("map_err: {:?}", mapped_err);

    // and_then(链式操作)
    let result = ok_val
        .and_then(|x| if x > 0 { Ok(x * 10) } else { Err("非正数".to_string()) });
    println!("and_then: {:?}", result);

    // is_ok / is_err
    println!("is_ok: {}, is_err: {}", ok_val.is_ok(), ok_val.is_err());

    // ok() / err() — 转换为 Option
    println!("ok(): {:?}", ok_val.ok());   // Some(42)
    println!("err(): {:?}", err_val.err()); // Some("错误")

    // ----------------------------------------------------------
    // 5. 自定义错误类型
    // ----------------------------------------------------------
    println!("\n=== 自定义错误 ===");

    match process_user_input("  ") {
        Ok(n) => println!("结果: {}", n),
        Err(e) => println!("错误: {}", e),
    }

    match process_user_input("abc") {
        Ok(n) => println!("结果: {}", n),
        Err(e) => println!("错误: {}", e),
    }

    match process_user_input("-5") {
        Ok(n) => println!("结果: {}", n),
        Err(e) => println!("错误: {}", e),
    }

    match process_user_input("42") {
        Ok(n) => println!("结果: {}", n),
        Err(e) => println!("错误: {}", e),
    }

    // ----------------------------------------------------------
    // 6. Box<dyn Error>(通用错误类型)
    // ----------------------------------------------------------
    // 当函数可能返回多种错误类型时,用 Box<dyn Error> 统一
    // 【适用场景】应用层代码、快速原型
    // 【不适用】库代码(应该用自定义错误类型)

    println!("\n=== Box<dyn Error> ===");

    match read_and_parse("config.txt") {
        Ok(n) => println!("值: {}", n),
        Err(e) => println!("错误: {}", e),
    }

    // ----------------------------------------------------------
    // 7. 多种错误类型的转换(From trait)
    // ----------------------------------------------------------
    println!("\n=== From 转换 ===");

    match read_config_typed("settings.txt") {
        Ok(val) => println!("配置值: {}", val),
        Err(e) => {
            match e {
                ConfigError::Io(ref io_err) => println!("IO 错误: {}", io_err),
                ConfigError::Parse(ref parse_err) => println!("解析错误: {}", parse_err),
                ConfigError::Validation(ref msg) => println!("验证错误: {}", msg),
            }
        }
    }

    // ----------------------------------------------------------
    // 8. 实用模式
    // ----------------------------------------------------------
    println!("\n=== 实用模式 ===");

    // 模式1: 收集 Result 的迭代器
    let strings = vec!["1", "2", "abc", "4"];

    // 遇到第一个错误就停止
    let numbers: Result<Vec<i32>, _> = strings.iter().map(|s| s.parse::<i32>()).collect();
    println!("collect Result: {:?}", numbers); // Err

    // 分离成功和失败
    let (successes, failures): (Vec<_>, Vec<_>) = strings
        .iter()
        .map(|s| s.parse::<i32>())
        .partition(Result::is_ok);

    let successes: Vec<i32> = successes.into_iter().map(Result::unwrap).collect();
    let failures: Vec<_> = failures.into_iter().map(Result::unwrap_err).collect();
    println!("成功: {:?}", successes);
    println!("失败: {:?}", failures);

    // 模式2: 忽略错误(只关心成功的)
    let numbers: Vec<i32> = strings
        .iter()
        .filter_map(|s| s.parse::<i32>().ok())
        .collect();
    println!("filter_map: {:?}", numbers);

    println!("\n=== 错误处理结束 ===");
}

// ----------------------------------------------------------
// ? 操作符示例
// ----------------------------------------------------------
fn read_config(path: &str) -> Result<String, io::Error> {
    let content = fs::read_to_string(path)?;  // 失败则提前返回 Err
    Ok(content.trim().to_string())
}

fn parse_number(s: &str) -> Result<i32, ParseIntError> {
    let n = s.trim().parse::<i32>()?;
    Ok(n * 2)
}

// ----------------------------------------------------------
// 自定义错误类型
// ----------------------------------------------------------
#[derive(Debug)]
enum InputError {
    Empty,
    InvalidFormat(ParseIntError),
    OutOfRange(i32),
}

impl fmt::Display for InputError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            InputError::Empty => write!(f, "输入为空"),
            InputError::InvalidFormat(e) => write!(f, "格式无效: {}", e),
            InputError::OutOfRange(n) => write!(f, "值 {} 超出范围 (0-100)", n),
        }
    }
}

// 实现 From,让 ? 自动转换错误类型
impl From<ParseIntError> for InputError {
    fn from(err: ParseIntError) -> InputError {
        InputError::InvalidFormat(err)
    }
}

fn process_user_input(input: &str) -> Result<i32, InputError> {
    let trimmed = input.trim();
    if trimmed.is_empty() {
        return Err(InputError::Empty);
    }

    let n: i32 = trimmed.parse()?;  // ParseIntError 自动转为 InputError

    if n < 0 || n > 100 {
        return Err(InputError::OutOfRange(n));
    }

    Ok(n)
}

// ----------------------------------------------------------
// Box<dyn Error>
// ----------------------------------------------------------
fn read_and_parse(path: &str) -> Result<i32, Box<dyn std::error::Error>> {
    let content = fs::read_to_string(path)?;  // io::Error
    let n = content.trim().parse::<i32>()?;   // ParseIntError
    Ok(n)
}

// ----------------------------------------------------------
// 完整的自定义错误类型(库级别)
// ----------------------------------------------------------
#[derive(Debug)]
enum ConfigError {
    Io(io::Error),
    Parse(ParseIntError),
    Validation(String),
}

impl fmt::Display for ConfigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ConfigError::Io(e) => write!(f, "IO 错误: {}", e),
            ConfigError::Parse(e) => write!(f, "解析错误: {}", e),
            ConfigError::Validation(msg) => write!(f, "验证错误: {}", msg),
        }
    }
}

impl std::error::Error for ConfigError {}

impl From<io::Error> for ConfigError {
    fn from(err: io::Error) -> ConfigError {
        ConfigError::Io(err)
    }
}

impl From<ParseIntError> for ConfigError {
    fn from(err: ParseIntError) -> ConfigError {
        ConfigError::Parse(err)
    }
}

fn read_config_typed(path: &str) -> Result<i32, ConfigError> {
    let content = fs::read_to_string(path)?;
    let value: i32 = content.trim().parse()?;
    if value < 0 {
        return Err(ConfigError::Validation("值不能为负".to_string()));
    }
    Ok(value)
}

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布