当前位置:Java -> Rust 中的 Try 块
我之前写过一篇关于在Rust中错误管理的库。本周,我想写一下有关try块,这是一个实验性特性。
?运算符的限制请查看上述文章,全面了解一般错误管理和?运算符。简而言之,?允许将其连接到返回Result的函数调用中:
Result包含一个值,则继续正常执行Result给调用函数。fn add(str1: &str, str2: &str) -> Result<i8, ParseIntError> {
Ok(str1.parse::<i8>()? + str2.parse::<i8>()?)
}
fn main() {
print!("{:?}", add("1", "2"));
print!("{:?}", add("1", "a"));
}
输出如下:
Ok(3)
Err(ParseIntError { kind: InvalidDigit })
请注意,定义函数的签名必须返回Result或Option。以下的代码块无法编译:
fn add(str1: &str, str2: &str) -> i8 {
str1.parse::<i8>()? + str2.parse::<i8>()?
}
the `?` operator can only be used in a function that returns `Result` or `Option`
我们必须手动解包以返回一个非包装类型,例如,i8而不是Option。
fn add(str1: &str, str2: &str) -> i8 {
let int1 = str1.parse::<i8>(); //1
let int2 = str2.parse::<i8>(); //1
if int1.is_err() || int2.is_err() { -1 } //2-3
else { int1.unwrap() + int2.unwrap() } //4
}
Result变量Result。在这种情况下,这不是一个好主意,但这是为了解释try块的拯救上面的示例虽然可行,但相当冗长。try块是一种实验性方法,旨在使其更加优雅。它允许将所有的错误检查"压缩"到单个块中:
#![feature(try_blocks)] //1
fn add(str1: &str, str2: &str) -> i8 {
let result = try {
let int1 = str1.parse::<i8>();
let int2 = str2.parse::<i8>();
int1.unwrap()? + int2.unwrap()? //2
};
if result.is_err() { -1 } //3
else { result.unwrap() } //4
}
Result,也使用?运算符然而,代码无法编译:
the `?` operator can only be applied to values that implement `Try`
i8不实现Try。既不是i8也不是Try属于我们的crate;自定义实现需要使用包装类型模式。幸运的是,已经有一些类型实现了Try:Result,Option,Poll和ControlFlow。
fn add(str1: &str, str2: &str) -> i8 {
let result: Result<i8, ParseIntError> = try { //1
str1.parse::<i8>()? + str2.parse::<i8>()? //2
};
if result.is_err() { -1 }
else { result.unwrap() }
}
try块中对Result使用?现在是允许的
我在20多年前的Java中了解了try块。Java需要它,因为异常是其错误处理系统的根本;而Rust不需要,因为它使用函数式编程来处理错误 —— 主要是Result。
?运算符基于Result类型,允许在返回Result的函数中进行短路操作。如果函数不返回Result,则需要大量的样板代码。实验性的try块减少了其中的一些代码。
推荐阅读: ChatGPT是什么?
本文链接: Rust 中的 Try 块