rust 使用`时,是否需要显式返回`Result`的`Ok`变体中的值?”“接线员?

b1payxdu  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(160)

在rust中,我们知道?运算符的工作方式类似于match表达式。如果Result是Ok,则从该表达式返回Ok变量中的结果,如果Result是Err,则从该表达式返回Err变量中的结果,并立即退出函数。现在在这段代码中:

#![allow(unused)]
fn main() {

    use std::fs::File;
    use std::io::{self, Read};

    fn propagated_error() -> Result<String, io::Error> {

        let mut file = File::open("hello.txt")?;
        let mut data = String::new();
        file.read_to_string(&mut data)?;
        Ok(data)
    }

    let data = propagated_error();
    match data{
        Ok(data) => println!("{data}"),
        Err(err) => panic!("{err}")
    }

}

如果我不像这样显式返回Ok(data),它会给出错误:

error[E0308]: mismatched types
   --> src/main.rs:119:30
    |
119 |     fn propagated_error() -> Result<String, io::Error> {
    |        ----------------      ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<String, Error>`, found `()`
    |        |
    |        implicitly returns `()` as its body has no tail or `return` expression
    |
    = note:   expected enum `Result<String, std::io::Error>`
            found unit type `()`

为什么????由于?运算符工作,?自动返回Ok变量中的值,所以为什么我必须像这样显式返回值:Ok(data)???
请帮我理清思路。

ckx4rj1h

ckx4rj1h1#

正如你自己所说,你必须显式返回一个Ok(T)变量。原因很简单。Result<T, E>T类型不同。它具有某种操作结果的语义含义,但对于编译器来说,它只是一个枚举。你也可以自己设计一个:

enum MyResult<T, E> {
    Ok(T),
    Err(E),
}

因此,当你说你的函数返回Result<T, E>时,你不能只返回T,因为类型不匹配。
问号运算符是传播error变量的快捷方式。你可以把它想象成一个宏(实际上它使用了一个不稳定的Try trait,但在这里理解这种机制并不重要),它扩展了以下代码:

let x = foo()?;

进入

let x = match foo() {
    Ok(x) => x,
    Err(e) => return Err(e.into()),
};

但是,它不会返回Ok变量中的数据,正如您之前所说的那样。
总结一下。你可以使用?提前从函数中返回Err变量,但是你需要在Ok变量中显式地 Package 你的“success”值,以便类型匹配。

brtdzjyr

brtdzjyr2#

这是因为?运算符基本上等价于:

match value {
    Ok(t) => t,
    Err(e) => return Err(e.into()),
}

它不仅在value是一个错误时返回错误,而且在value不是错误时删除Ok Package 器。这意味着它将Result<T, _>转换为T,因此:

fn proof() -> Result<(), String> {
    Ok(())?
}

变成(大致):

fn proof() -> Result<(), String> {
    match Ok(()) {
        Ok(t) => t,
        Err(e) => return Err(e.into),
    }
}

匹配的结果是()类型的值,但函数需要Result<(), String>,因此必须将其 Package 在Ok

fn proof() -> Result<(), String> {
    Ok(Ok(())?)
}

现在看起来真的很奇怪,所以让我们用一个类型为Fn() -> Result<(), &'static str>的易错函数交换内部的Ok

fn proof() -> Result<(), String> {
    Ok(fallible_func()?)
}

现在希望它更清楚一点,?转换并返回一个错误,如果没有,则给出T的值。

相关问题