Rust错误

1.rust错误分类

  1. 可恢复错误
    • Result<T, E>方法
    • 如文件未找到,可以再次尝试
  2. 不可恢复错误
    • panic!宏方法
    • 索引超出

2.不可恢复错误panic!

2.1 当panic!宏执行时候步骤

  1. 你的程序会打印错误
  2. 展开(unwind)、清理调用栈(Stack)
  3. 退出程序

2.2 panic!宏展开和中止说明

默认是展开的

  1. 程序展开调用(工作量大)
    • rust沿着调用栈往回走
    • 清理每个遇到的函数中的数据
  2. 立即中止调用栈
    • 不进行清理,直接停止程序
    • 内存需要OS进行清理

2.3 panic!宏切换到中止

在cargo.toml中适当的profile部分这种

cargo.toml文件

[profile.release]
panic='abort'

main.rs文件

fn main() {
    panic!("err")
}

2.4 什么时候使用panic!

  1. 什么时候使用panic!
    • 在定义一个可能失败的函数时,优先考虑返回Result
    • 否者panic!
  2. 编写实例、原先代码、测试
    • 可以使用panic!
    • unwrap
    • expect
  3. 代码处于存坏状态时
    • 如: 非法值,程序不能正常运行

3.可修复错误Result

3.1 说明

操作成功返回OK里面的数据,操作失败返回Err里的数据

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

3.2 错误匹配

3.2.1 match进行匹配

use std::fs::File;
fn main(){
    let f = File::open("hello.txt");
    let _ff = match f {
        Ok(file) => file,
        Err(error) => {
            panic!("无法打开文件 {:?}", error)
        }
    };
}

3.2.2 匹配不同错误

如果处理错误,那么错误又会有成功和错误,不停的嵌套会有很多match

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

fn main(){
    let f = File::open("hello.txt");
    let _ff = match f {
        Ok(file) => file,
        Err(error) => match error.kind() {
            // 如果找不到那就创建文件
            ErrorKind::NotFound => match File::create("hello.txt") {
                // 在创建文件中还会有成功和失败
                Ok(fc) => fc,
                Err(e) => panic!("Create File Error: {:?}", e),
            },
            // 其他错误
            other_err => panic!("Open File Error: {:?}", other_err),
        }
    };
}

3.3 unwrap错误处理

如果Resuil的值OK返回Ok里的值,如果是Err就调用panic!
unwrap不能输入自定义错误信息

use std::fs::File;

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

3.4 expect错误处理

和unwrap类型,但是可以自定义错误信息,如果是Err就调用panic!

use std::fs::File;

fn main(){
    let _f = File::open("hello.txt").expect("找不到文件 hello.txt");
}

3.5 传播错误

通过Result<T, E>返回错误

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

fn read_file(file_name: &str) -> Result<String, io::Error> {
    println!("file_name: {}", file_name);
    let f = File::open(file_name);
    // 如果文件找不到报错,那会会返回Err(e)
    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();
    // 文件打开后读取内容到s上
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

fn main() {
    let f = read_file("hello.txt");
    println!("f: {:?}", f)
}

3.6 ?运算符

?运算符一般用于返回 Result<T, E> 或者 Option 类型的表达式。当表达式返回 Ok(T) 或者 Some(T) 时,? 运算符会提取出其中的值 T;若返回 Err(E) 或者 None,它会立即从当前函数返回这个错误或 None。(优化多match问题3.5)

  • 注意事项
    1. ? 运算符只能在返回 Result<T, E> 或者 Option 类型的函数中使用。
    2. 若 ? 运算符处理的错误类型 E 与函数返回的错误类型不匹配,会产生编译错误。
use std::fs::File;
use std::io;
use std::io::Read;

fn read_file(file_name: &str) -> Result<String, io::Error> {
    println!("file_name: {}", file_name);
    // ?如果执行错误返回Err
    let f = File::open(file_name)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

fn main() {
    let f = read_file("hello.txt");
    println!("f: {:?}", f)
}

3.7 ?与from函数

Trait std::convert::From上的from函数
用于错误之间的转换
被?所应用的错误,会被隐式的被from函数处理
用于:针对不同错误原因,返回同一种错误类型
只要每个错误类型实现了转换为返回的错误类型的from函数

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

fn read_file(file_name: &str) -> Result<String, io::Error> {
    println!("file_name: {}", file_name);
    let mut s = String::new();
    // 当open和read_to_string都成功时候才执行
    // 失败了就返回Err
    File::open(file_name)?.read_to_string(&mut s)?;
    Ok(s)
}

fn main() {
    let f = read_file("hello.txt");
    println!("f: {:?}", f)
}

3.8 自定义错误实现from

#[derive(Debug)]
struct MyErr(String);

// 实现 From<i32> 转换
impl From<i32> for MyErr {
    fn from(err_code: i32) -> Self {
        match err_code {
            1 => Self(format!("程序异常: {}", err_code)),
            128 => Self(format!("终端退出: {}", err_code)),
            133 => Self(format!("网络不稳定: {}", err_code)),
            150 => Self(format!("账号限制: {}", err_code)),
            _ => Self(format!("未知错误: {}", err_code)),
        }
        
    }
}

fn test_err(retrun_num: i32) -> Result<String, i32> {
    if retrun_num == 0 {
        Ok(String::from("ok"))
    } else {
        Err(retrun_num)
    }
}

// type MyResult<T> = Result<String, MyErr>可以使用别名

fn test_myerr(retrun_num: i32) -> Result<String, MyErr> {
    // 如果报错了,那么会把i32转MyErr
    let s = test_err(retrun_num)?;
    // 需要返回Ok(String)
    Ok(s)
}

fn main() {
    let retrun_num = 111;
    let res = test_myerr(retrun_num);
    println!("res: {:?}", res);
}

3.9 使用enum

通常使用enum创建自定义错误类型

use std::error::Error;
use std::fs::File;
use std::io::{self, Read};
use std::num::ParseIntError;

// 自定义错误类型
#[derive(Debug)]
enum MyError {
    IoError(io::Error),
    ParseError(ParseIntError),
}

// 为自定义错误类型实现 std::error::Error 特征
impl Error for MyError {}

// 为自定义错误类型实现 std::fmt::Display 特征
impl std::fmt::Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            MyError::IoError(e) => write!(f, "IO 错误: {}", e),
            MyError::ParseError(e) => write!(f, "解析错误: {}", e),
        }
    }
}

// 实现 From<io::Error> 转换
impl From<io::Error> for MyError {
    fn from(error: io::Error) -> Self {
        MyError::IoError(error)
    }
}

// 实现 From<ParseIntError> 转换
impl From<ParseIntError> for MyError {
    fn from(error: ParseIntError) -> Self {
        MyError::ParseError(error)
    }
}

// 读取文件并解析为整数的函数
fn read_file_and_parse() -> Result<i32, MyError> {
    let mut file = File::open("example.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    let num = contents.trim().parse::<i32>()?;
    Ok(num)
}

fn main() {
    match read_file_and_parse() {
        Ok(num) => println!("读取并解析的整数是: {}", num),
        Err(e) => println!("发生错误: {}", e),
    }
}

3.10 ?只能用于返回类型为Result的函数

use std::fs::File;

// main返回的不是Result,所以执行会报错
fn main() {
    let _f = File::open(file_name)?;
}

3.11 main函数也可是Result类型

use std::fs::File;
use std::error::Error;

// Box<dyn Error>是trait对象,任何可能的错误类型
fn main() -> Result<(). Box<dyn Error>> {
    let _f = File::open(file_name)?;
    Ok(())
}
posted @ 2026-08-10 10:01  lxd670  阅读(14)  评论(0)    收藏  举报