3.9 KiB
To panic! or Not to panic!
什么使用返回panic?什么时候Result(类似 try-catch)?
在示例、原型代码和测试等情况下,更合适的做法是编写具有panic的代码,而不是返回Result。
个人认为,开发时除了能控制逻辑的代码可以多返回panic。而发布产品时尽量不返回panic,因为会导致程序停止(健壮性低)。
panic的各种情况
- 示例、原型代码和测试时,使用panic。
- 比编译器掌握更多信息的情况,可以使用Result,结果可控。但如果IP地址字符串来自用户而不是硬编码到程序中,因此确实有失败的可能性,我们肯定希望以
Result
更稳健的方式处理。.
错误处理指南
当代码可能最终处于糟糕的状态时,让代码返回panic是明智的。
如果有人调用您的代码并传入了没有意义的值,最好返回一个错误,以便库的用户可以决定在这种情况下他们想要做什么。然而,如果继续下去可能是不安全的或有害的,最好的选择可能是呼叫恐慌!并提醒使用您的库的人注意他们代码中的错误,以便他们在开发过程中修复它。同样,恐慌!如果您正在调用超出您控制的外部代码,并且它返回您无法修复的无效状态,则通常适用。
然而,当预期失败时,返回Result比制造恐慌更合适!调用。例如,向解析器提供格式错误的数据或HTTP请求返回指示您已达到速率限制的状态。在这些情况下,返回Result表明失败是调用代码必须决定如何处理的预期可能性。
创建用于验证的自定义类型
猜数字旧版代码: 如果程序只对 1 到 100 之间的值进行操作是绝对关键的,并且它有许多满足此要求的函数,那么在每个函数中进行这样的检查将是乏味的(并且可能会影响表现)。
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1..=100);
loop {
// --snip--
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
if guess < 1 || guess > 100 {
println!("The secret number will be between 1 and 100.");
continue;
}
match guess.cmp(&secret_number) {
// --snip--
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}
更好的方式:
#![allow(unused)]
fn main() {
pub struct Guess {
value: i32,
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}
}
运行图:
总结
Rust的错误处理特性旨在帮助您编写更健壮的代码。panic!宏信号表明您的程序处于无法处理的状态,并允许您告诉进程停止,而不是试图继续处理无效或不正确的值。Result枚举使用Rust的类型系统来指示操作可能失败,而您的代码可以从中恢复。您可以使用Result告诉调用您的代码的代码,它也需要处理潜在的成功或失败。使用panic!和Result在适当的情况下将使您的代码在面对不可避免的问题时更加可靠。