【发布时间】:2015-08-10 21:46:07
【问题描述】:
我注意到 Rust 没有异常。如何在 Rust 中进行错误处理以及常见的陷阱是什么?有没有办法用加注、接球、再加注和其他东西来控制流程?我发现这方面的信息不一致。
【问题讨论】:
标签: error-handling rust
我注意到 Rust 没有异常。如何在 Rust 中进行错误处理以及常见的陷阱是什么?有没有办法用加注、接球、再加注和其他东西来控制流程?我发现这方面的信息不一致。
【问题讨论】:
标签: error-handling rust
Rust 通常通过两种方式解决错误:
不可恢复的错误。一旦你panic!,就是这样。您的程序或线程中止,因为它遇到了无法解决的问题并且其不变量已被违反。例如。如果您在 UTF-8 字符串中发现无效序列。
可恢复的错误。在某些文档中也称为失败。您不会惊慌,而是发出Option<T> 或Result<T, E>。在这些情况下,您可以在有效值Some(T)/Ok(T) 或无效值None/Error(E) 之间进行选择。一般None作为null的替代品,表示缺少值。
现在是困难的部分。申请。
有时处理Option 会让人头疼,几乎可以保证你得到一个值而不是一个错误。
在这些情况下,使用unwrap 完全没问题。 unwrap 将 Some(e) 和 Ok(e) 转换为 e,否则会出现恐慌。 Unwrap 是一种将可恢复的错误变为不可恢复的工具。
if x.is_some() {
y = x.unwrap(); // perfectly safe, you just checked x is Some
}
在if-block 内,解包非常好,因为它永远不会恐慌,因为我们已经检查了它是Some 和x.is_some()。
如果您正在编写库,不鼓励使用unwrap,因为当它发生恐慌时,用户无法处理错误。此外,未来的更新可能会更改不变量。想象一下,如果上面的例子有if x.is_some() || always_return_true()。不变量会改变,unwrap 可能会恐慌。
? 运算符/try! 宏? 运算符或try! 宏是什么?一个简短的解释是,它要么返回 Ok() 内的值,要么过早返回错误。
以下是运算符或宏扩展为的简化定义:
macro_rules! try {
($e:expr) => (match $e {
Ok(val) => val,
Err(err) => return Err(err),
});
}
如果你这样使用它:
let x = File::create("my_file.txt")?;
let x = try!(File::create("my_file.txt"));
它会将其转换为:
let x = match File::create("my_file.txt") {
Ok(val) => val,
Err(err) => return Err(err),
};
缺点是你的函数现在返回Result。
Option 和Result 有一些方便的方法允许以可理解的方式链接和处理错误。 and、and_then、or、or_else、ok_or、map_err等方法
例如,您可以使用默认值,以防您的值被破坏。
let x: Option<i32> = None;
let guaranteed_value = x.or(Some(3)); //it's Some(3)
或者,如果您想将您的 Option 变成 Result。
let x = Some("foo");
assert_eq!(x.ok_or("No value found"), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or("No value found"), Err("No value found"));
这只是您可以做的事情的简要介绍。更多解释,请查看:
【讨论】:
如果您需要终止一些独立的执行单元(网络请求、视频帧处理、GUI 事件、要编译的源文件)但不是完整的应用程序,有一个函数 std::panic::catch_unwind 调用关闭,如果发生恐慌,就会捕获解除恐慌的原因。
let result = panic::catch_unwind(|| {
panic!("oh no!");
});
assert!(result.is_err());
我不会授予此闭包对任何可能超过它的变量或任何其他全局状态的写访问权限。
文档还说该函数也可能无法捕捉到某种恐慌。
【讨论】: