You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.9 KiB
114 lines
3.9 KiB
1 year ago
|
# To panic! or Not to panic!
|
||
|
|
||
|
什么使用返回panic?什么时候Result(类似 try-catch)?
|
||
|
|
||
|
在示例、原型代码和测试等情况下,更合适的做法是编写具有panic的代码,而不是返回Result。
|
||
|
|
||
|
个人认为,开发时除了能控制逻辑的代码可以多返回panic。而发布产品时尽量不返回panic,因为会导致程序停止(健壮性低)。
|
||
|
|
||
|
## panic的各种情况
|
||
|
|
||
|
1. 示例、原型代码和测试时,使用panic。
|
||
|
2. 比编译器掌握更多信息的情况,可以使用Result,结果可控。但如果IP地址字符串来自用户而不是硬编码到程序中,因此*确实*有失败的可能性,我们肯定希望以`Result`更稳健的方式处理。.
|
||
|
|
||
|
![image-20230208225653099](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230208225653099.png)
|
||
|
|
||
|
|
||
|
|
||
|
## 错误处理指南
|
||
|
|
||
|
当代码可能最终处于糟糕的状态时,让代码返回panic是明智的。
|
||
|
|
||
|
如果有人调用您的代码并传入了没有意义的值,最好返回一个错误,以便库的用户可以决定在这种情况下他们想要做什么。然而,如果继续下去可能是不安全的或有害的,最好的选择可能是呼叫恐慌!并提醒使用您的库的人注意他们代码中的错误,以便他们在开发过程中修复它。同样,恐慌!如果您正在调用超出您控制的外部代码,并且它返回您无法修复的无效状态,则通常适用。
|
||
|
|
||
|
然而,当预期失败时,返回Result比制造恐慌更合适!调用。例如,向解析器提供格式错误的数据或HTTP请求返回指示您已达到速率限制的状态。在这些情况下,返回Result表明失败是调用代码必须决定如何处理的预期可能性。
|
||
|
|
||
|
|
||
|
|
||
|
## 创建用于验证的自定义类型
|
||
|
|
||
|
猜数字旧版代码: 如果程序只对 1 到 100 之间的值进行操作是绝对关键的,并且它有许多满足此要求的函数,那么在每个函数中进行这样的检查将是乏味的(并且可能会影响表现)。
|
||
|
|
||
|
```rust
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
更好的方式:
|
||
|
|
||
|
```rust
|
||
|
#![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
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
运行图:
|
||
|
|
||
|
![image-20230209001139397](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230209001139397.png)
|
||
|
|
||
|
## 总结
|
||
|
|
||
|
Rust的错误处理特性旨在帮助您编写更健壮的代码。panic!宏信号表明您的程序处于无法处理的状态,并允许您告诉进程停止,而不是试图继续处理无效或不正确的值。Result枚举使用Rust的类型系统来指示操作可能失败,而您的代码可以从中恢复。您可以使用Result告诉调用您的代码的代码,它也需要处理潜在的成功或失败。使用panic!和Result在适当的情况下将使您的代码在面对不可避免的问题时更加可靠。
|