当前位置: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 块