rust 错误

Created

2024-04-29 22:15:08

Updated

2024-10-05 14:38:32

1 Unrecoverable Errors

越界

fn main() {
    let v = vec![1, 2, 3];

    v[99];
}

1.1 一些宏

panic!()
fn main() {
    panic!("crash and burn"); // 后面的不会执行
    println!("1");
}
fn not_yet_implemented() {
    // 标记尚未实现的功能。
    // 当执行到这个宏时,程序会 panic,并显示一条消息
    unimplemented!();
}
fn feature_not_ready_yet() {
    // 用于标记代码中的“待办事项”
    // 即开发者知道这部分代码需要在未来完成
    todo!("Implement this feature");
}
fn unreachable() {
    // 表明某个代码路径实际上不应该被执行到
    // 如果执行到这个宏,程序会触发一个 panic
    unreachable!();
}

fn main() {
    let x = 5;
    assert!(x < 10); // 如果 x >= 10,则会 panic
    let a = 5;
    let b = 6;
    assert_eq!(a, b); // 如果 a != b,则会 panic
    assert_ne!(a, b); // 如果 a == b,则会 panic
}

2 Recoverable Errors

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

2.1 match

use std::fs::File;

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

    let greeting_file = match greeting_file_result {
        Ok(file) => file, // 返回给 greeting_file
        Err(error) => {
            // 直接panic
            panic!("Problem opening the file: {:?}", error);
        }
    };
}
use std::fs::File;
use std::io::ErrorKind;

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

    let greeting_file = match greeting_file_result {
        Ok(file) => file,
        Err(error) => match error.kind() {
            // 匹配不同的错误
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Problem creating the file: {:?}", e),
            },
            other_error => {
                panic!("Problem opening the file: {:?}", other_error);
            }
        },
    };
}

2.2 unwrap_or_else

使用 Result<T, E> 的方法 unwrap_or_else

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("hello.txt").unwrap_or_else(|error| {
                panic!("Problem creating the file: {:?}", error);
            })
        } else {
            panic!("Problem opening the file: {:?}", error);
        }
    });
}

2.3 unwrap

use std::fs::File;

fn main() {
    // unwrap 方法会返回一个 Result 枚举,
    // 如果 Result 枚举是 Ok 类型,则 unwrap 会返回 Ok 中的值,
    // 如果 Result 枚举是 Err 类型,则 unwrap 会panic Err 中的错误信息, 程序退出
    let greeting_file = File::open("hello.txt").unwrap();
}

2.4 expect

相比unwrap 就是能定义输出的错误信息

use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt")
        .expect("hello.txt 文件不存在 ");
}

2.5 ?

use std::fs::File;
use std::io::{self, Read};
fn main() {
    read_username_from_file().unwrap();
}
fn read_username_from_file() -> Result<String, io::Error> {
    let username_file_result = File::open("hello.txt");
    // 错误的情况, 返回 result<String,Error>
    let mut username_file = match username_file_result {
        Ok(file) => file,
        // return 会退出函数, 返回Err(e) 给read_username_from_file
        Err(e) => return Err(e),
    };

    let mut username = String::new();
    // 不管结果如何, 都返回 ,让给调用者处理
    match username_file.read_to_string(&mut username) {
        Ok(_) => Ok(username),
        Err(e) => Err(e),
    }   // 注意这里是没有 ; 的, 因为要返回 result<T,E>
}

上面的写法, 你会发现, 有同样类似的逻辑, 就是将结果result 给调用者自己处理, 使用? 简化代码

use std::fs::File;
use std::io::{self, Read};
fn main() {
    read_username_from_file().unwrap();
}
fn read_username_from_file() -> Result<String, io::Error> {
    // \? 放在 Result 类型的返回值上
    // 如果返回值是 Ok,那么Ok包含的value 会被返回, 程序继续执行
    // 如果返回值是 Err, 则 当前函数执行完毕, return Err ,Err作为函数的返回值
    let mut username_file = File::open("hello.txt")?;
    let mut username = String::new();
    let s = username_file.read_to_string(&mut username)?;
    println!("s:=={}", s); // 读取的字节书
    Ok(username)
}

更简洁

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    let mut username = String::new();

    File::open("hello.txt")?.read_to_string(&mut username)?;

    Ok(username)
}

当然 标准库 提供了 上面的需求的更好的方法, 知道就行, 这不是我们讨论的点.

use std::fs;
use std::io;

fn read_username_from_file() -> Result<String, io::Error> {
    fs::read_to_string("hello.txt")
}
Caution
  • ? 只能被用在 函数里
  • 只能用在 Result, Option, 或者其他 实现了 FromResidual的 类型上

下面代码报错了

use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt")?;
}

3 开源错误处理库

3.1 anyhow1

3.1.1 源码分析

3.1.2 使用

use std::fs;

use anyhow::Result as anyRes;
fn main() {
}

// 使用anyhow 我们可以不关心具体的错误
fn get_file_info()(file_path: &str) -> anyRes<String> {
    // ? 表示 正确返回Ok() 里的值, 如有错误,则直接return Err(e),函数 退出
    let info = fs::read_to_string(file_path)?;
    // 正常的情况, 需要用Ok包起来 变成 Result 返回
    Ok(info)
}

3.2 thiserror2

Back to top