文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
6.2 可恢复
可恢复性(recoverable)错误通常指一种状态。比如打开文件时,没找到,应该新建。
显然,最终如何处理,由调用方负责。
没有异常(exception),对于可恢复性错误,返回 Result<T, E>
对象。
- 通过函数签名,很容易知道是否会发生错误。
- 编译器对调用返回值进行检查,警告未处理行为。
- 相比 C 和 Go,Rust 有更优雅的错误传播方式。
和元组一次返回多个值不同,
Result
要么返回Ok
,要么返回Err
。它们都携带有载荷,代表返回值或具体错误。
enum Result<T, E> { Ok(T), Err(E), }
用 match
匹配和解构较为繁琐,可直接调用 Result
相关方法。
is_ok
,is_err
ok
,err
unwrap
,except
unwrap_or
,unwrap_or_else
as_ref
,as_mut
fn test(x: i32) -> Result<i32, &'static str> { if x > 0 { Ok(x) } else { Err("error") } } fn main() { match test(1) { Ok(x) => println!("{:?}", x), Err(e) => println!("{:?}", e), } let _x = test(0).unwrap_or_else(|err| { // unwrap, expect panic!("{:?}", err); }); }
提示:
- 创建有意义的别名。
type io::Result<T> = Result<T, io::Error>
。 - 定义具体错误类型。
Result<T, io::Error>
。 - 只是判断是否出错,
Result<(), error>
。
传播
通过 return Err
将错误按调用堆栈传递出去。
fn div(x: i32, y: i32) -> Result<i32, &'static str> { if y != 0 { Ok(x / y) } else { Err("divide by zero") } } fn test(x: i32, y: i32) -> Result<i32, &'static str> { let z = div(x, y); if z.is_err() { return z; } // 传播! z } fn main() { test(3, 0).unwrap(); // 处理错误! }
用 ?
操作符简化传播代码。
- 用于
Result<T, E>
返回类型的函数调用。 - 解构
Ok
值,或立即return Err
继续传播。 - 传播
Err
关联类型必须相同(或自动转换)。
使用
?
操作符,意味着当前函数(caller)也必须返回Result<T, E>
类型。其中
T
类型可不同,但E
必须相同。如不想继续传播,可调用unwrap
等方法。也可用于返回
Option<T>
的函数调用,区别在于向外return None
。
fn test(x: i32, y: i32) -> Result<i32, &'static str> { let z: i32 = div(x, y)?; Ok(z) } // let z: i32 = match div(x, y) { // Ok(v) => v, // Err(e) => return Err(e), // }
链式调用。
use std::fs::File; use std::io::prelude::*; fn test() -> std::io::Result<()> { let mut contents = String::new(); File::open("foo.txt")?.read_to_string(&mut contents)?; Ok(()) } fn main() { // 无法使用 ? 操作符,除非修改 main 签名, // 改为 fn main() -> Result<(), E>。 test().unwrap(); }
集中处理。
use std::io; use std::io::prelude::*; use std::fs::File; fn main() { // 匿名函数调用。 (|| -> io::Result<()> { let mut f = File::open("foo.txt")?; // Result<File> let mut buf = [0; 10]; let n = f.read(&mut buf)?; // Result<usize> println!("{:?}", &buf[..n]); Ok(()) })().unwrap_or_else(|e| { // 集中错误处理。 println!("{:?}", e); }); }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论