在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)
???
请帮我理清思路。
2条答案
按热度按时间ckx4rj1h1#
正如你自己所说,你必须显式返回一个
Ok(T)
变量。原因很简单。Result<T, E>
与T
的类型不同。它具有某种操作结果的语义含义,但对于编译器来说,它只是一个枚举。你也可以自己设计一个:因此,当你说你的函数返回
Result<T, E>
时,你不能只返回T
,因为类型不匹配。问号运算符是传播error变量的快捷方式。你可以把它想象成一个宏(实际上它使用了一个不稳定的Try trait,但在这里理解这种机制并不重要),它扩展了以下代码:
进入
但是,它不会返回
Ok
变量中的数据,正如您之前所说的那样。总结一下。你可以使用
?
提前从函数中返回Err
变量,但是你需要在Ok
变量中显式地 Package 你的“success”值,以便类型匹配。brtdzjyr2#
这是因为
?
运算符基本上等价于:它不仅在
value
是一个错误时返回错误,而且在value
不是错误时删除Ok
Package 器。这意味着它将Result<T, _>
转换为T
,因此:变成(大致):
匹配的结果是
()
类型的值,但函数需要Result<(), String>
,因此必须将其 Package 在Ok
中现在看起来真的很奇怪,所以让我们用一个类型为
Fn() -> Result<(), &'static str>
的易错函数交换内部的Ok
。现在希望它更清楚一点,
?
转换并返回一个错误,如果没有,则给出T
的值。