错误处理
不可恢复的错误与panic!宏
rust语言的错误处理:
- rust语言具有较高的可靠性,有完备的错误处理机制,大部分情况下,能在编译是提示错误,并处理完错误。
- rust没有类似异常处理的机制
错误的分类:
- 可恢复错误:使用Result<T, E>机制,如文件未找到,可再次尝试。
- 不可恢复:bug,使用panic!宏处理,当执行该宏时,程序立即终止,如索引越界访问。
当panic!宏执行时:
- 程序会打印一个错误信息
- 展开(unwind)、清理调用栈(Stack)
- 退出程序
为应对panic,展开或中止(abort)调用栈。
默认情况下,当panic发生时,会执行:
- 程序展开调用栈(工作量大):rust沿着调用栈往回走,清理每个遇到的函数中的数据。
- 或立即中止调用栈:不进行清理,直接停止程序,内存则需要OS进行清理。
如果想让二进制文件更小,可把设置从“展开”改为“中止”:
- 在Cargo.toml中适当的profile部分设置:panic = 'abort'
[profile.release]
panic = 'abort'
使用panic!产生的回溯信息
- panic!可能出现在自己开发的代码和依赖的代码中,可通过panic!函数回溯信息来定位引起问题的代码。
- 可通过设置环境变量RUST_BACKTRACE获得回溯信息。
- 为了获取带有调试信息的回溯,必须启用调试符号(执行Cargo run命令时不带 --release)。
fn main() {
panic!("panic test");
}
/* 运行结果:
thread 'main' panicked at 'panic test', src\main.rs:2:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\hello_cargo.exe` (exit code: 101)
*/
另一个例子:
fn main() {
let v = vec![1, 2];
v[5];
}
/* 运行结果:
thread 'main' panicked at 'index out of bounds: the len is 2 but the index is 5', src\main.rs:3:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
*/
根据提示,如果设置RUST_BACKTRACE=1环境变量就可显示backtrace,就可看到真正发生panic的地方了
>set RUST_BACKTRACE=1 && cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.01s
Running `target\debug\hello_cargo.exe`
thread 'main' panicked at 'index out of bounds: the len is 2 but the index is 5', src\main.rs:3:5
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\std\src\panicking.rs:593
1: core::panicking::panic_fmt
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\core\src\panicking.rs:67
2: core::panicking::panic_bounds_check
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be/library\core\src\panicking.rs:162
3: core::slice::index::impl$2::index<i32>
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\core\src\slice\index.rs:261
4: alloc::vec::impl$12::index<i32,usize,alloc::alloc::Global>
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\alloc\src\vec\mod.rs:2675
5: hello_cargo::main
at .\src\main.rs:3
6: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/5680fa18feaa87f3ff04063800aec256c3d4b4be\library\core\src\ops\function.rs:250
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\hello_cargo.exe` (exit code: 101)
可见第5个栈信息是测试代码,其他是库代码。提示显示可设置RUST_BACKTRACE=full可获得一详细的backtrace。
可恢复的错误与Result
通常情况下,会对程序运行可能的错误进行处理,而不是让程序终止运行,而且很多错误也是通过一定处理后便可继续运行,rust中采用Result枚举来处理错误。
Result枚举的定义
enum Result<T, E> {
OK(T),
Err(E),
}
- T: 操作成功的情况,OK变体里返回数据的类型。
- E:操作失败的情况,Err变体里返回错误的类型。
处理Result的一种方式:使用match表达式。
和Option枚举一样,Result及其变体也是由prelude带入作用域的,所以使用OK和Err变体时不需要写成Result::OK的格式了。
use std::fs::File;
fn main() {
let f = File::open("test.txt"); // 返回值就是个Result类型,std::result::Result<std::fs::File, std::io::Error>类型
// 打开文件可能发生文件不存在的错误,如果成功则返回std::fs::File类型,不存在或无权限等导致不成功则返回io::Err错误
let fp = match f {
Ok(file) => file, // 如果成功则返回file实体,使得fp = file
Err(error) => {
panic!("Err msg: {:?}", error) // 这里可不用;号,加上也可
},
};
}
// 运行结果:thread 'main' panicked at 'Err msg: Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }', src\main.rs:8:13
还可匹配不同的错误
如上述文件打开可能的错误是std::io::Error类型,也是一个struct,提供一错误类型方法kind(),返回值是一std::io::ErrorKind枚举,里边的变体用于描述可能发生IO错误,比如NotFound错误。
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("test.txt");
let fp = match f {
Ok(file) => file,
Err(error) => match error.kind() { // 如果打开失败则创建文件
ErrorKind::NotFound => match File::create("test.txt") { // 创建也可能失败,所以需要继续match
Ok(fc) => fc,
Err(e) => panic!("Err creat file: {:?}", e),
},
other_err => panic!("Err open file: {:?}", other_err),
},
};
}
运行结果是在项目目录下创建了一个文件test.txt。
上述代码中使用了很多match,代码很原始,可使用闭包(closure)。
Result<T, E>有很多方法:可接收闭包作为参数,使用match实现,可使上述代码更简洁,减少match嵌套。
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("test.txt").unwrap_or_else(|error| {
if error.kind() == ErrorKind::NotFound {
File::create("test.txt").unwrap_or_else(|error| {
panic!("err create file: {:?}", error);
})
} else {
panic!("Err open file: {:?}", error);
}
});
}
unwrap方法
unwrap:match表达式的一个快捷方法。
标签:std,Err,rs,18,Result,错误处理,main,panic,rust From: https://www.cnblogs.com/UFO-blogs/p/17787788.html