如何在Rust中进行错误处理以及常见的陷阱是什么?

aemubtdh  于 2023-04-21  发布在  其他
关注(0)|答案(2)|浏览(113)

我注意到Rust没有异常。如何在Rust中进行错误处理以及常见的陷阱是什么?是否有方法通过raise,catch,reraise和其他东西来控制流?我发现这方面的信息不一致。

oiopk7p5

oiopk7p51#

Rust通常以两种方式解决错误:

*不可恢复的错误。一旦你panic!,就是这样。你的程序或线程中止,因为它遇到了一些它无法解决的问题,并且它的不变量被违反。例如,如果你在应该是UTF-8字符串的字符串中找到无效的序列。
*可恢复错误。在某些文档中也称为失败。您不会惊慌失措,而是发出Option<T>Result<T, E>。在这些情况下,您可以选择分别为有效值Some(T)/Ok(T)或无效值None/Error(E)。通常None用作null的替换,表明该值丢失。

接下来是最难的部分。申请。

解包

有时候处理Option是件很麻烦的事,你几乎可以保证得到一个值而不是一个错误。
在这些情况下,使用unwrap是完全可以的。unwrapSome(e)Ok(e)转换为e,否则它会死机。Unwrap是一个将可恢复的错误转换为不可恢复的工具。

if x.is_some() {
    y = x.unwrap(); // perfectly safe, you just checked x is Some
    // ...
}

if-块内部,可以很好地解包,因为它永远不会死机,因为我们已经检查过它是Somex.is_some()
如果你正在编写一个库,不建议使用unwrap,因为当它死机时,用户无法处理错误。此外,未来的更新可能会更改不变量。想象一下,如果上面的例子有if x.is_some() || always_return_true()。不变量会更改,unwrap可能会死机。
在这个例子中,你应该使用ìf let

if let Some(y) = x {
    // ...
}

?运算符/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

组合器

OptionResult有一些方便的方法,允许链接和以可理解的方式处理错误。方法如andand_thenoror_elseok_ormap_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"));

这只是你可以做的事情的一个简短的浏览。更多的解释,请查看:

gfttwv5a

gfttwv5a2#

如果你需要终止一些独立的执行单元(一个web请求,一个视频帧处理,一个GUI事件,一个要编译的源文件),但不是所有的应用程序,有一个函数std::panic::catch_unwind,它调用一个闭包,如果发生一个解卷恐慌,它会捕获解卷恐慌的原因。

let result = panic::catch_unwind(|| {
    panic!("oh no!");
});
assert!(result.is_err());

我不会授予这个闭包对任何可能超过它的变量或任何其他全局状态的写访问权限。
文档还说,该函数也可能无法捕获某些类型的恐慌。

相关问题