Rust使用Result<T, E>
定义可恢复错误。
介绍
Result 枚举的定义
enum Result<T, E> {
Ok(T),
Err(E),
}
说明:
- T/E为泛型
- T:操作成功时,对应 Ok 变体里返回的数据类型
- E:操作失败时,对应 Err 变体里返回的数据类型
示例
Result 使用 match 表达式处理,且 Result 及其变体有 prelude 导入作用域
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("foo.md");
let f = match f {
Ok(file) => file,
// Err(error) => {
// panic!("Error open file {:?}", error); // Error open file Os { code: 2, kind: NotFound, message: "No such file or directory" }
// }
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("foo.md") {
Ok(fc) => fc,
Err(error) => panic!("create file err: {:?}", error),
},
o => panic!("err: {:?}", o),
},
};
println!("{:?}", f);
}
说明:
- 上述示例使用很多
match
,比较麻烦。可以使用闭包(closure)
优化代码
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let f = File::open("foo.md").unwrap_or_else(|error| {
if error.kind() == ErrorKind::NotFound {
File::create("foo.md").unwrap_or_else(|error| {
panic!("create file err: {:?}", error);
})
} else {
panic!("err: {:?}", error);
}
});
println!("{:?}", f);
}
unwrap
unwrap 是 match 表达式的一个快捷方法:
- 若 Result 结果是 Ok,返回 Ok 里的值
- 若 Result 结果是 Err,调用 panic! 宏,且错误不可以自定义
use std::fs::File;
fn main() {
let f = File::open("foo.md").unwrap();
println!("{:?}", f);
}
expect
expect 和 unwrap 类似,且支持指定错误信息
use std::fs::File;
fn main() {
let f = File::open("foo.md").expect("open file foo.md err");
println!("{:?}", f);
}
传播错误
在函数中错误处理有两种方式:
use std::fs::File;
use std::io;
use std::io::Read;
fn read_user_from_file() -> Result<String, io::Error> {
let f = File::open("foo.md");
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),
}
}
fn main() {
let content = read_user_from_file();
match content {
Ok(c) => println!("{}", c),
Err(e) => println!("err: {}", e),
}
}
? 运算符
Rust 中使用 ? 运算符
来快捷的传播错误,上面的例子,通过 ? 运算符
重构如下:
use std::fs::File;
use std::io;
use std::io::Read;
fn read_user_from_file() -> Result<String, io::Error> {
let mut f = File::open("foo.md")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let content = read_user_from_file();
match content {
Ok(c) => println!("{}", c),
Err(e) => println!("err: {}", e),
}
}
? 运算符
作用如下:
- 如果 Result 是
Ok()
,将 Ok 里的值作为表达式的结果,程序继续执行 - 如果 Result 是
Err(e)
,则 Err(e)
作为整个函数的返回值
? 运算符
与 from 函数
:
- Trait
std::convert::From
的 from 函数
用于错误之间的转换 - 被
?
所应用的错误,会隐式的备 from
函数处理- 当 ? 调用 from 函数时,它所接收的错误类型会被转化为当前函数返回类型所定义的错误类型
- 因此,常用于针对不同错误原因,返回同一种错误类型,且该错误类型需要实现目标错误类型的
from 函数
链式调用
上述示例重新优化,如下:
use std::fs::File;
use std::io;
use std::io::Read;
fn read_user_from_file() -> Result<String, io::Error> {
let mut s = String::new();
File::open("foo.md")?.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let content = read_user_from_file();
match content {
Ok(c) => println!("{}", c),
Err(e) => println!("err: {}", e),
}
}
说明:
? 运算符
只能用于返回 Result 的函数,注意:- 默认
fn main() {}
函数的返回值为 ()
,因此不能在 main()
函数中使用 ? 运算符
main()
函数可以指定返回值,此时可以在 main()
函数中使用 ? 运算符
,示例:
use std::fs::File;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("foo.md")?;
println!("{:?}", f);
Ok(())
}
说明:
Box<dyn Error>
为 trait 对象,可以理解为任何可能的错误类型