Rust错误
1.rust错误分类
- 可恢复错误
Result<T, E>方法- 如文件未找到,可以再次尝试
- 不可恢复错误
panic!宏方法- 索引超出
2.不可恢复错误panic!
2.1 当panic!宏执行时候步骤
- 你的程序会打印错误
- 展开(unwind)、清理调用栈(Stack)
- 退出程序
2.2 panic!宏展开和中止说明
默认是展开的
- 程序展开调用(工作量大)
- rust沿着调用栈往回走
- 清理每个遇到的函数中的数据
- 立即中止调用栈
- 不进行清理,直接停止程序
- 内存需要OS进行清理
2.3 panic!宏切换到中止
在cargo.toml中适当的profile部分这种
cargo.toml文件
[profile.release]
panic='abort'
main.rs文件
fn main() {
panic!("err")
}
2.4 什么时候使用panic!
- 什么时候使用panic!
- 在定义一个可能失败的函数时,优先考虑返回Result
- 否者panic!
- 编写实例、原先代码、测试
- 可以使用panic!
- unwrap
- expect
- 代码处于存坏状态时
- 如: 非法值,程序不能正常运行
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)
- 注意事项
- ? 运算符只能在返回 Result<T, E> 或者 Option
类型的函数中使用。 - 若 ? 运算符处理的错误类型 E 与函数返回的错误类型不匹配,会产生编译错误。
- ? 运算符只能在返回 Result<T, E> 或者 Option
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(())
}

浙公网安备 33010602011771号