rust:错误处理

错误处理

Rust 将错误分为两类:

  • 可恢复的错误 - 使用 Result<T, E>
  • 不可恢复的错误 - 使用 panic!

panic! 用于遇到无法处理的错误时终止程序:

fn main() {
    panic!("程序发生了严重错误!崩溃!");
    // 后续代码不会执行
}

常见的 panic 场景:

fn main() {
    let v = vec![1, 2, 3];
    v[99]; // 索引越界 -> panic!
}

Result<T, E> 是处理可恢复错误的标准方式:

enum Result<T, E> {
    Ok(T),    // 成功
    Err(E),   // 失败
}
use std::fs::File;
use std::io::ErrorKind;
 
fn main() {
    let f = File::open("hello.txt");
 
    let f = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("创建文件失败: {:?}", e),
            },
            other_error => {
                panic!("打开文件失败: {:?}", other_error)
            }
        },
    };
}

简单快速的错误处理方式:

fn main() {
    // 成功则返回值,失败则 panic
    let f = File::open("hello.txt").unwrap();
 
    // 类似 unwrap,但自定义 panic 信息
    let f = File::open("hello.txt")
        .expect("无法打开 hello.txt");
}

? 运算符是错误传播的语法糖:成功则解包,失败则提前返回错误。

use std::fs::File;
use std::io::{self, Read};
 
fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("hello.txt")?;  // 失败时 return Err
    let mut s = String::new();
    f.read_to_string(&mut s)?;             // 失败时 return Err
    Ok(s)
}
 
fn main() {
    match read_username_from_file() {
        Ok(name) => println!("用户名: {}", name),
        Err(e) => println!("读取失败: {}", e),
    }
}

? 还可以链式调用:

fn read_username() -> Result<String, io::Error> {
    let mut s = String::new();
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}

Option<T> 用于值可能不存在的情况:

fn find_first_word(s: &str) -> Option<&str> {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return Some(&s[..i]);
        }
    }
    None // 没有空格返回 None
}
 
fn main() {
    match find_first_word("hello world") {
        Some(word) => println!("第一个词: {}", word),
        None => println!("没有找到空格"),
    }
 
    // Option 也可用 ? 运算符
    fn try_find(s: &str) -> Option<&str> {
        let word = find_first_word(s)?; // None 则提前返回
        Some(word)
    }
}

ResultOption 提供了丰富的组合子方法:

fn main() {
    // map - 转换内部值
    let result: Result<i32, &str> = Ok(5);
    let mapped = result.map(|x| x * 2); // Ok(10)
 
    // and_then - 链式操作
    let result = result.and_then(|x| Ok(x + 3)); // Ok(8)
 
    // unwrap_or - 提供默认值
    let default: Result<i32, &str> = Err("error");
    let value = default.unwrap_or(0); // 0
 
    // ok_or - Option 转 Result
    let option: Option<i32> = Some(5);
    let result = option.ok_or("值不存在"); // Ok(5)
}
use std::fmt;
 
#[derive(Debug)]
enum MyError {
    IoError(std::io::Error),
    ParseError(String),
}
 
impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            MyError::IoError(e) => write!(f, "IO 错误: {}", e),
            MyError::ParseError(s) => write!(f, "解析错误: {}", s),
        }
    }
}
 
impl std::error::Error for MyError {} // 实现标准 Error trait
use std::io::{self, BufRead};
 
fn read_and_parse() -> Result<i32, String> {
    let mut line = String::new();
    io::stdin().read_line(&mut line)
        .map_err(|e| format!("读取输入失败: {}", e))?;
 
    line.trim().parse::<i32>()
        .map_err(|_| "无法解析为整数".to_string())
}
 
fn main() {
    println!("请输入一个整数:");
    match read_and_parse() {
        Ok(n) => println!("你输入了: {}", n),
        Err(e) => println!("错误: {}", e),
    }
}
  • panic! 用于不可恢复的错误
  • Result<T, E> 处理可恢复的错误
  • unwrapexpect 快速解包(失败时 panic)
  • ? 运算符传播错误,写出简洁代码
  • mapand_thenunwrap_or 等组合子丰富处理方式
  • 自定义错误类型实现 Error trait

该主题尚不存在

您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。

  • rust/错误处理.txt
  • 最后更改: 2026/06/15 15:44
  • 张叶安