使用问号进行 Rust 错误处理

RustRustBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将学习 Rust 中的 ? 运算符,它允许我们通过返回 Err 而不是使程序恐慌(panic)来简化错误处理。我们还将探索 try! 宏,它在 ? 运算符引入之前实现了类似的功能。

注意:如果实验未指定文件名,你可以使用任何你想要的文件名。例如,你可以使用 main.rs,通过 rustc main.rs &&./main 来编译并运行它。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/ErrorHandlingandDebuggingGroup(["Error Handling and Debugging"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/ErrorHandlingandDebuggingGroup -.-> rust/error_propagation("Error Propagation") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} rust/integer_types -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} rust/string_type -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} rust/function_syntax -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} rust/expressions_statements -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} rust/error_propagation -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} rust/operator_overloading -.-> lab-99243{{"使用问号进行 Rust 错误处理"}} end

介绍 ?

有时候,我们只想要 unwrap 的简便性,又不想有程序恐慌(panic)的可能性。到目前为止,当我们真正想要的是取出变量时,unwrap 却迫使我们进行越来越深的嵌套。这正是 ? 的用途。

一旦发现 Err,有两种有效的操作:

  1. panic!,我们已经决定尽可能避免这种情况
  2. return,因为 Err 意味着无法处理

? 几乎[^†]等同于一个 unwrap,它在遇到 Err 时返回而不是使程序恐慌(panic)。让我们看看如何简化之前使用组合器的示例:

use std::num::ParseIntError;

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    let first_number = first_number_str.parse::<i32>()?;
    let second_number = second_number_str.parse::<i32>()?;

    Ok(first_number * second_number)
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    print(multiply("10", "2"));
    print(multiply("t", "2"));
}

try!

在有 ? 之前,相同的功能是通过 try! 宏实现的。现在推荐使用 ? 运算符,但在查看旧代码时你可能仍然会看到 try!。上一个示例中的相同 multiply 函数使用 try! 看起来会是这样:

// 要在使用 Cargo 时无错误地编译并运行此示例,请将 `Cargo.toml` 文件的 `[package]` 部分中的 `edition` 字段的值更改为 "2015"。

use std::num::ParseIntError;

fn multiply(first_number_str: &str, second_number_str: &str) -> Result<i32, ParseIntError> {
    let first_number = try!(first_number_str.parse::<i32>());
    let second_number = try!(second_number_str.parse::<i32>());

    Ok(first_number * second_number)
}

fn print(result: Result<i32, ParseIntError>) {
    match result {
        Ok(n)  => println!("n is {}", n),
        Err(e) => println!("Error: {}", e),
    }
}

fn main() {
    print(multiply("10", "2"));
    print(multiply("t", "2"));
}

总结

恭喜你!你已经完成了“介绍 ?”实验。你可以在 LabEx 中练习更多实验来提升你的技能。