包有为

十三叔!大事不好了!皇上驾崩了!(Panic)

包龙星

胡说八道!这种不可恢复的错误直接崩溃就算了。

如果是“没钱买饼”这种小错误 (Result),我们还是可以处理一下的嘛。

豹子头 (雷豹)

我不管!要么给钱,要么死!(unwrap)

Rust 错误处理:天塌下来当被盖

Rust 将错误分为两大类:可恢复错误 (如文件未找到) 和 不可恢复错误 (如数组越界)。

💥 不可恢复错误:panic!

当遇到无法挽回的问题时,程序会直接崩溃退出。

fn main() {
    panic!("皇上驾崩啦!");
}

🛡️ 可恢复错误:Result<T, E>

大多数错误都是可以处理的。Rust 使用 Result 枚举来返回成功或失败。

enum Result<T, E> {
    Ok(T),
    Err(E),
}

use std::fs::File;

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

    let f = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("文件打不开: {:?}", error);
        },
    };
}

🔪 简写:unwrap 和 expect

如果你确信不会出错,或者懒得处理错误(直接崩溃),可以用这两个方法。

let f = File::open("hello.txt").unwrap(); // 出错就 panic
let f = File::open("hello.txt").expect("文件必须存在!"); // 出错 panic 并打印信息

🛠️ Result 常用招式

除了 matchunwrap,还有很多优雅的处理方式:

❓ 传播错误:? 运算符

如果函数里处理不了错误,可以把错误抛给调用者。

use std::io;
use std::io::Read;
use std::fs::File;

fn read_username_from_file() -> Result<String, io::Error> {
    let mut s = String::new();
    // 如果 open 失败,直接返回 Err
    File::open("hello.txt")?.read_to_string(&mut s)?; 
    Ok(s)
}
🚑

动手时刻:吃饼防毒

编写一个吃饼程序。

  1. 编写函数 eat_cake(is_poisoned: bool) -> Result<String, String>
  2. 如果 is_poisoned 为 true,返回 Err("有毒!我不吃!".to_string())
  3. 否则返回 Ok("真香!".to_string())
  4. 在 main 函数中调用,并用 match 处理结果。
查看参考答案 (点击揭榜)

fn eat_cake(is_poisoned: bool) -> Result<String, String> {
    if is_poisoned {
        Err("有毒!我不吃!".to_string())
    } else {
        Ok("真香!".to_string())
    }
}

fn main() {
    let result = eat_cake(true);
    
    match result {
        Ok(msg) => println!("{}", msg),
        Err(e) => println!("报错了: {}", e),
    }
}
                    

成就解锁:【银针试毒】 🥢