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.

3.9 KiB

To panic! or Not to panic!

什么使用返回panic?什么时候Result(类似 try-catch)?

在示例、原型代码和测试等情况下,更合适的做法是编写具有panic的代码,而不是返回Result。

个人认为,开发时除了能控制逻辑的代码可以多返回panic。而发布产品时尽量不返回panic,因为会导致程序停止(健壮性低)。

panic的各种情况

  1. 示例、原型代码和测试时,使用panic。
  2. 比编译器掌握更多信息的情况,可以使用Result,结果可控。但如果IP地址字符串来自用户而不是硬编码到程序中,因此确实有失败的可能性,我们肯定希望以Result更稳健的方式处理。.

image-20230208225653099

错误处理指南

当代码可能最终处于糟糕的状态时,让代码返回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
    }
}
}

运行图:

image-20230209001139397

总结

Rust的错误处理特性旨在帮助您编写更健壮的代码。panic!宏信号表明您的程序处于无法处理的状态,并允许您告诉进程停止,而不是试图继续处理无效或不正确的值。Result枚举使用Rust的类型系统来指示操作可能失败,而您的代码可以从中恢复。您可以使用Result告诉调用您的代码的代码,它也需要处理潜在的成功或失败。使用panic!和Result在适当的情况下将使您的代码在面对不可避免的问题时更加可靠。