Rust第九节 - 错误处理

9 错误处理

在Rust中,我们的错误处理有两种,分为可恢复处理和不可恢复处理。

9.1 不可恢复错误处理

9.1.1 panic

我们首先举一个例子,这个例子会引发panic的报错,例如:

rust 复制代码
let arr = vec![1, 2, 3];
println!("{}", arr[100]);

当我们出现越界访问的时候,这个时候会触发panic报错,导致程序崩溃,我们在开发的时候应该尽量注意。这是个不可恢复的处理。

9.1.2 错误回溯

当我们需要查看错误回溯的时候,我们可以使用RUST_BACKTRACE=1 cargo run命令,例如我们手动触发一个panic!报错:

rust 复制代码
fn main(){ // 在根文件中使用 panic! 抛出错误
    panic!("Error...")
}

// 控制台执行命令  RUST_BACKTRACE=1 cargo run

9.2 可恢复错误处理

我们在日常的开发中,更多的情况是,针对不同的错误进行不同的处理。

9.2.1 Result 枚举

Rust在预模块中替我们引入Result枚举,里面包含了OKErr两个变体的,OK表示正确变体,Err表示错误变体。接下来让我们来手动处理错误。

9.2.2 手动处理错误

我们尝试写一段代码来打开一个不存在的文件,例如:

rust 复制代码
use std::fs::read;
let f = read("./hello-world.txt");
println!("{:?}", f)

因为我们这个文件是不存在的,所以这个时候会返回一个Err变体,这个时候我们可以使用match去处理,当我们的文件不同时,我们就创建这个文件,例如:

rust 复制代码
use std::fs;
use std::io::ErrorKind;

let f = fs::File::open("./hello-world.txt");
match f {
    Ok(data) => {
        println!("{:?}", data);
    }
    Err(error) => {
        return match error.kind() {
            ErrorKind::NotFound => {
                let create_data = fs::File::create("./hello-world.txt");
                match create_data {
                    Ok(file_data) => {
                        println!("{:?}", file_data);
                    }
                    Err(err) => {
                        println!("{}", err);
                    }
                }
            }
            _ => {
                println!("{}", error);
            }
        };
    }
}

上面我们手动去处理读取文件失败的错误,然后创建文件,但是我们也要对创建文件去手动做错误处理,显得太麻烦了,于是我们可以用以下的方法去简化

9.2.3 unwrap和expect快速处理错误

对于有返回Result枚举的方法、函数等,我们都可以使用unwrapexpect去处理。 对于unwrap,就相当于我们使用match去处理错误,只不过它会返回一个Rust默认的错误,例如:

rust 复制代码
use std::fs;

fs::File::open("./hello-world.txt").unwrap()

expect,我们则可以穿入一个字符串,提示我们想提示的内容,例如:

rust 复制代码
fs::File::open("./hello-world.txt").expect("创建文件失败");

9.2.4 向上返回结果和错误体

对于刚刚嵌套的问题,我们可以将其拆分成为多个函数,然后把我们读取或者创建文件后的Result变体想外部抛出,然后上一层去获取并且处理。我们现封装一个读取文件的函数,例如:

rust 复制代码
use std::io::ErrorKind;
use std::{fs, io};

// 读取文件
fn read_file(path: &str) -> Result<String, io::Error> {
    let content = match fs::File::open(path) {
        Ok(data) => data,
        Err(error) => {
            println!("{:?}", error);
            return Err(error);
        }
    };
    return Ok(content);
}

// 创建文件
fn create_file(path: &str) {
    match fs::File::create(path) {
        Ok(data) => {
            println!("{:?}", data);
        }
        Err(error) => {
            println!("{:?}", error)
        }
    }
}

// 在最外层处理封装函数的逻辑
let content = match read_file("./hello-world.txt") {
    Ok(data) => data,
    Err(error) => {
        return match error.kind() {
            ErrorKind::NotFound => {
                create_file("./hello-world.txt");
            }
            _ => {
                println!("其他错误");
            }
        };
    }
};

9.2.5 优化处理错误处理(?)

即使我们做了函数的封装,让嵌套变少了,但是还是显得很麻烦,那还没有更简单的方法呢?当然有,我们有语法糖?,它会将存储在Ok内部的值返回给外部的变量。如果出现了错误,?就会提前结束整个函数的执行,并将任何可能的Err值返回给函数调用者,例如:

rust 复制代码
fn read_file() -> Result<String, io::Error> {
    let mut str: String = String::new();
    fs::File::open("./hello-world.txt")?.read_to_string(&mut str)?;
    println!("{}", str);
    Ok(str)
}

使用该方法,如果文件不存在,会自动把错误抛出,而不会panic崩溃。 所有返回Result或者Option枚举的,我们都可以使用该语法糖处理。

相关推荐
计算机安禾2 分钟前
【c++面向对象编程】第21篇:运算符重载基础:语法、规则与不可重载的运算符
java·前端·c++
__log14 分钟前
Vue 3 核心技术深度解析:从“会用API“到“懂原理、能表达“
前端·javascript·vue.js
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_52:(深入 XPathExpression 接口)
开发语言·前端·javascript·ui·html·音视频
UXbot1 小时前
AI 原型工具零设计基础操作指南与功能解析(2026)
前端·ui·产品经理·原型模式·web app
yuzhiboyouye2 小时前
VO一般java后端怎么转换成前端想要的数据
java·前端·状态模式
小脑斧1232 小时前
从范式重构到工程落地:OpenTiny NEXT 引领前端智能化新范式
前端·hermesagent·opentiny next
小江的记录本2 小时前
【AI大模型选型指南】《2026年5月(最新版)国内外主流AI大模型选型指南》(企业版)
前端·人工智能·后端·ai作画·aigc·ai编程·ai写作
幽络源小助理2 小时前
最新轻量美化表白墙系统源码v2.0_带后台版_附搭建教程
前端·开源·源码·php源码
qq_381338502 小时前
前端状态管理新范式:Zustand、Jotai 与 Preact Signals 深度对比
前端·arcgis