- Rust的可靠性:错误处理——大部分情况下,在编译时提示错误并处理
- 错误的分类:
- 可恢复
- 例如文件未找到,可再次尝试
- 不可恢复
- bug,例如访问索引超出范围
- panic宏
fn main() {
// panic!("crash and burn");
let v = vec![1, 2, 3];
v[99];
}
- set RUST_BACKTRACE=full && cargo run:返回具体的回溯信息
- 和Option枚举一样,Result及其变体也是有preclude代入作用域
use std::fs::File;
fn main() {
// panic!("crash and burn");
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => {
panic!("Err opening file {:?}", error);
},
};
}
- 匹配不同的错误(创建文档)
use std::{fs::File, io::ErrorKind};
fn main() {
// panic!("crash and burn");
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!("Error create file: {:?}", e),
},
other_error => panic!("Error opening the file: {:?}", other_error),
},
};
}
- match很有用,但是很原始(和上一段代码效果一样)
use std::{fs::File, io::ErrorKind};
fn main() {
// panic!("crash and burn");
File::open("hello.txt").unwrap_or_else(|error| {
if error.kind() == ErrorKind::NotFound {
File::create("hello.txt").unwrap_or_else(|error| {
panic!("Error creating file: {:?}", error);
})
} else {
panic!("Error opening file: {:?}", error);
}
});
}
- unwrap:match表达式的一个快捷方法;
- expect:和unwrap类似,但可以指定错误信息
传播错误
use std::{fs::File, io, io::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是函数的返回值
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
fn main() {
let result = read_username_from_file();
println!("{:?}", result);
}
- ?运算符:传播错误的一种快捷方式
(下面代码与上一段效果相同)
use std::{fs::File, io, io::Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?;
let mut s = String::new();
// 下面这个match是函数的返回值
f.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let result = read_username_from_file();
println!("{:?}", result);
}
- ?与from函数(被隐式处理)
- 当?调用from函数时:
- 它所接收的错误类型会转化为当前函数返回类型所定义的错误类型
- 用于针对不同错误原因,返回同一种错误类型
- 只要每个错误类型实现了转换为所返回的错误类型的from函数
还是一样的效果:
use std::{fs::File, io, io::Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let result = read_username_from_file();
println!("{:?}", result);
}
- 开始优雅起来了,main函数也能修改返回值
Box<dyn Error>是trait对象:任何可能的错误类型
use std::{fs::File, error::Error};
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("hello.txt")?;
Ok(())
}
什么时候使用panic!
- 总体原则:
- 在定义一个可能失败的函数时,优先考虑返回Result
- 否则就panic!
总结
基础快学完了,内容也学一半了,感觉Rust真的是一门很好的语言,继续加油!