38·错误处理进阶

? 运算符与错误传播

? 运算符与错误传播

学习目标

  1. 掌握 ? 运算符
  2. 理解错误自动转换
  3. 掌握链式错误处理

核心概念

基本用法

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

fn read_number() -> Result<i32, io::Error> {
    let content = fs::read_to_string("number.txt")?;  // 失败则返回 Err
    let number: i32 = content.trim().parse().map_err(|e: ParseIntError| {
        io::Error::new(io::ErrorKind::InvalidData, e)
    })?;
    Ok(number)
}

// 等价于
fn read_number_verbose() -> Result<i32, io::Error> {
    let content = match fs::read_to_string("number.txt") {
        Ok(c) => c,
        Err(e) => return Err(e),
    };
    // ...
    Ok(42)
}

main 函数使用 ?

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let content = std::fs::read_to_string("config.txt")?;
    println!("{}", content);
    Ok(())
}

链式调用

use std::fs;
use std::num::ParseIntError;

fn process() -> Result<i32, Box<dyn std::error::Error>> {
    let content = fs::read_to_string("data.txt")?;
    let number: i32 = content.trim().parse()?;
    Ok(number * 2)
}

自定义 From 实现自动转换

#[derive(Debug)]
enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError) }

impl From<std::io::Error> for MyError {
    fn from(e: std::io::Error) -> Self { MyError::Io(e) }
}

impl From<std::num::ParseIntError> for MyError {
    fn from(e: std::num::ParseIntError) -> Self { MyError::Parse(e) }
}

fn read_number() -> Result<i32, MyError> {
    let content = std::fs::read_to_string("number.txt")?;  // io::Error → MyError
    let number: i32 = content.trim().parse()?;              // ParseIntError → MyError
    Ok(number)
}

小结

语法含义
expr?成功继续,失败返回 Err
From< E>错误类型自动转换
Box<dyn Error>通用错误类型

练习编辑器

rust
Loading...