这个问号操作员是关于什么的?

Ang*_*gel 58 rust

我正在阅读以下文档File:

//..
let mut file = File::create("foo.txt")?;
//..
Run Code Online (Sandbox Code Playgroud)

什么是?在这条线?我不记得以前在Rust Book中看过它了.

Mat*_* M. 96

您可能已经注意到,Rust没有例外.它有恐慌,但它们的功能有限(它们不能携带结构化信息),并且不鼓励它们用于错误处理(它们用于不可恢复的错误).

在Rust中,错误处理使用Result.一个典型的例子是:

fn halves_if_even(i: i32) -> Result<i32, Error> {
    if i % 2 == 0 { Ok(i/2) } else { Err(/* something */) }
}

fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = match halves_if_even(i) {
        Ok(i) => i,
        e => return e,
    };

    // use `i`
}
Run Code Online (Sandbox Code Playgroud)

这很棒,因为:

  • 在编写代码时,您不会意外忘记处理错误,
  • 在阅读代码时,您可以立即看到可能存在错误.

然而,它并不理想,因为它非常冗长.这就是问号运算符的?用武之地.

以上可以改写为:

fn do_the_thing(i: i32) -> Result<i32, Error> {
    let i = halves_if_even(i)?;

    // use `i`
}
Run Code Online (Sandbox Code Playgroud)

这更简洁.

是什么?在这里所做的相当于match上述表示的.简而言之:它解压缩Resultif if并返回错误,如果没有.

这有点神奇,但错误处理需要一些魔法来减少样板,并且与异常不同,它可以立即看到哪些函数调用可能会或可能不会出错:那些装饰的?.

也可以看看:

  • 如果您能稍微扩展一下答案,那就太好了,例如讨论函数的返回类型必须与您尝试“解包”的类型相匹配,例如`Result` 或`Option`。 (6认同)

snn*_*snn 28

它是一个解包Result<T, E>Option<T>值的后缀运算符。

如果应用于Result<T, E>,它会解开结果并为您提供内部值,从而将错误传播到调用函数。

let number = "42".parse::<i32>()?;
println!("{:?}", number); // 42
Run Code Online (Sandbox Code Playgroud)

当应用于 an 时Option<T>,它会传播None到调用者,让您处理 Some 分支的内容。

let val = Some(42)?;
println!("{:?}", val); // 42
Run Code Online (Sandbox Code Playgroud)

?运算符只能在返回的函数中使用ResultOption如下所示:

use std::num::ParseIntError;

fn main() -> Result<(), ParseIntError> {
    let number = "42".parse::<i32>()?;
    println!("{:?}", number);
    Ok(())
}
Run Code Online (Sandbox Code Playgroud)

这是 Rust 提供的便利,它消除了样板代码并使函数的实现更简单。

  • 不要与实际的“.unwrap()”混淆,后者在出现错误时会出现恐慌。 (24认同)

Yil*_*maz 12

它用于propagating errors. 有时我们编写的代码可能会失败,但我们不想立即捕获并处理错误。如果您有太多代码来处理每个地方的错误,您的代码将不可读。相反,如果发生错误,我们可能想让调用者处理它。我们希望错误在调用堆栈中向上传播。

 // file type is Result if "?" is not used
 // file:Result<File,Error>
 let mut file = File::create("foo.txt");

 // file type is File if "?" is used
 // file:File
 let mut file = File::create("foo.txt")?;
 // if an error occurs, code after this line will not be executed
 // function will return the error
 // if we do not return here, the program will continue execution even though an error occurred. This could lead to unexpected behavior or incorrect results.
Run Code Online (Sandbox Code Playgroud)

的行为?取决于该函数返回成功结果还是错误结果:

  • 如果成功,它将解开 Result 以获取其中的成功值。值被分配给变量file
  • 如果结果是错误,则该错误不会分配给变量file。函数将错误返回给调用者

使用?与此代码相同的方法

let mut file = match File::create("foo.txt") {
        Err(why) => panic!("couldn't create {}: {}", display, why),
        Ok(file) => file,
    };
Run Code Online (Sandbox Code Playgroud)

?对于 Option 类型也有类似的作用。在返回 Option 的函数中,您可以使用 ? 在 None 的情况下解包值并提前返回: