错误处理
panic
panic
打印错误消息,展开堆栈,并退出程序。
fn main() {
let divisor = 0;
if divisor == 0 {
// 如果除数为零,则使用自定义错误消息引发 panic
panic!("Attempted to divide by zero!");
}
let result = 42 / divisor;
println!("Result: {}", result);
}
Option
在 std
库中,使用 Option<T>
枚举来表示可能不存在的情况。它有两种选项:
Some(T)
: 类型为T
的元素None
: 没有元素
这两个选项可以通过 match
显式处理,也可以通过 unwrap
隐式处理。隐式处理将返回内部元素或引发 panic
。
fn main() {
let some_value: Option<&str> = Some("literank");
let unwrapped_value = some_value.unwrap();
println!("Unwrapped value: {}", unwrapped_value);
// 使用 None 变体创建一个 Option
let none_value: Option<i32> = None;
// 尝试展开 None 变体(将引发 panic)
let unwrapped_none = none_value.unwrap();
println!("This line will not be reached due to the panic above");
}
使用 ? 解包
你可以通过使用 match
语句来解包 Option
,但使用 ?
运算符通常更方便。
fn process_option_value(value: Option<i32>) -> Option<i32> {
// 使用 `?` 运算符展开 Option,如果是 None 则提前返回 None
let unwrapped_value = value?;
let result = unwrapped_value * 2;
Some(result)
}
Result
Result
是 Option
类型的高配版本,其用于描述可能的错误而不是可能的值缺失。
Result<T, E>
可能有两种结果:
Ok(T)
:成功后类型为T
的元素Err(E)
:失败后包含类型为E
元素的错误
#[derive(Debug)]
struct CustomError;
fn divide(a: i32, b: i32) -> Result<i32, CustomError> {
if b == 0 {
Err(CustomError)
} else {
Ok(a / b)
}
}
在 main 中使用 Result
Result
类型也可以是 main
函数的显式返回类型。
fn main() -> Result<(), CustomError> {
// 如果失败,? 运算符将错误在主函数中返回
let result = divide(58, 2)?;
println!("Result is: {}", result);
Ok(())
}
?
几乎等同于 unwrap
,但在遇到 Err
时,它 return
而不是 panic
。
迭代 Result
map
操作是有可能失败的。
fn main() {
let strings = vec!["literank", "58", "42"];
let numbers: Vec<_> = strings
.into_iter()
.map(|s| s.parse::<i32>())
.collect();
println!("Results: {:?}", numbers);
// Results: [Err(ParseIntError { kind: InvalidDigit }), Ok(58), Ok(42)]
}
可以使用 filter_map
忽略失败的项。
fn main() {
let strings = vec!["literank", "58", "42"];
let numbers: Vec<_> = strings
.into_iter()
.filter_map(|s| s.parse::<i32>().ok())
.collect();
println!("Results: {:?}", numbers);
// Results: [58, 42]
}
还可以使用 map_err
将失败的项收集起来。
fn main() {
let strings = vec!["42", "literank", "58", "300", "18"];
let mut errors = vec![];
let numbers: Vec<_> = strings
.into_iter()
.map(|s| s.parse::<u8>())
.filter_map(|r| r.map_err(|e| errors.push(e)).ok())
.collect();
println!("Numbers: {:?}", numbers);
// Numbers: [42, 58, 18]
println!("Errors: {:?}", errors);
// Errors: [ParseIntError { kind: InvalidDigit }, ParseIntError { kind: PosOverflow }]
}
或者,可以使用 partition
以更简单的方式执行此操作。
fn main() {
let strings = vec!["42", "literank", "58", "300", "18"];
let (numbers, errors): (Vec<_>, Vec<_>) = strings
.into_iter()
.map(|s| s.parse::<i32>())
.partition(Result::is_ok);
println!("Numbers: {:?}", numbers);
// Numbers: [Ok(42), Ok(58), Ok(300), Ok(18)]
println!("Errors: {:?}", errors);
// Errors: [Err(ParseIntError { kind: InvalidDigit })]
}
Result
实现了 FromIterator
,以便将结果的向量 (Vec<Result<T, E>>
) 转换为带有向量的结果 (Result<Vec<T>, E>
)。一旦遇到 Result::Err
,迭代终止。
fn main() {
let strings = vec!["literank", "58", "42"];
let numbers: Result<Vec<_>, _> = strings
.into_iter()
.map(|s| s.parse::<i32>())
.collect();
println!("Results: {:?}", numbers);
// Results: Err(ParseIntError { kind: InvalidDigit })
}
代码挑战
尝试修改编辑器中提供的代码,以处理
divide_numbers
中的错误。
Loading...
> 此处输出代码运行结果