错误
错误在软件中无可否认事实,rust很多特性处理错误清晰,能够在编译代码之前采取行动,使得程序更加健壮, rust中将错误归类两种类型可恢复错误(报告错误并且重试,逻辑错误) , 不可恢复错误(bug)
rust 中没有异常,有可以恢复错误Resu<T> , 不可恢复错误panic!
panic! 宏
栈展开(回溯栈并且清理遇到内存)/ 终止由系统清理内存
在Cargo.toml增加panic = 'abort'
切换到终止模式
fn main() {
panic!("crash and burn");
}
$ cargo run
Compiling panic v0.1.0 (file:///projects/panic)
Finished dev [unoptimized + debuginfo] target(s) in 0.25s
Running `target/debug/panic`
thread 'main' panicked at 'crash and burn', src/main.rs:2:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
panic 显示出现问题地方
- panic!的backtrace 确认bug
backtrace: 执行到当前位置被调用函数的列表 ,JAVA中调用链关系
fn main() {
let v = vec![1, 2, 3];
v[99]; // 尝试越界处理, 出现panic ,C++ 中内存溢出出现安全漏洞
}
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\/library\std\src\panicking.rs:498
1: core::panicking::panic_fmt
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\/library\core\src\panicking.rs:116
2: core::panicking::panic_bounds_check
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\/library\core\src\panicking.rs:84
3: core::slice::index::impl$2::index<i32>
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\library\core\src\slice\index.rs:189
4: core::slice::index::impl$0::index<i32,usize>
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\library\core\src\slice\index.rs:15
5: alloc::vec::impl$15::index<i32,usize,alloc::alloc::Global>
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\library\alloc\src\vec\mod.rs:2520
6: rust_helloword::main
at .\src\main.rs:4
7: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a\library\core\src\ops\function.rs:227
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\rust_helloword.exe` (exit code: 101)
Result 类型
enum Result<T, E> {
Ok(T),
Err(E),
}
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) =>file,
Err(error) => panic!("problem open in the file {:?}", error),
};
}
- z不同方式处理不同类型错误
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("hello.txt");
let f = match f {
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)
}
},
};
}
- 失败panic 简写 unwarp / expec
一般采用excep 原因在于except 提供一个好的错误信息并且妙明意图更加容易对于panic跟踪
let f = File::open("hello.txt").expect("Failed to open hello.txt");
使用 expect 而不是 unwrap 并提供一个好的错误信息可以表明你的意图并更易于追踪 panic 的根源
- 传播错误
更好控制代码调用,调用者拥有更多的信息或者逻辑决定处理错误
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
?运算符进行简写,?之后直接使用调用链方式进一步缩短代码,类似JS ECA6 使用? 进行调用链.
? 运算符只能被用于返回值与 ? 作用的值相兼容的函数`
let mut s = String::new()
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
使用场景
- 示例代码,代码原型和测试适合使用panic
- 别人调用你代码传递一个没有意义参数 panic,调用外部代码,并且返回了一个无法修复的无效状态使用 panic 非常合适;
- 当错误预期会出现 使用Result 更好
新创建类似验证实例
#新创建一个新类型验证不是重复检测
// 结构体的函数
impl Guess {
// 构造函数
pub fn new(value: i32) -> Guess {
if value <1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}