`?` 运算符只能在返回 `Result` 或 `Option` 的异步块中使用。

15
我正在学习 Rust 并尝试通过发送一些 POST 数据来爬取一个随机网站,但是我遇到了一堆错误信息,如下所示:
error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)

37  | |     let text = res.text().await?;
    | |                                ^ cannot use the `?` operator in an async block that returns `()`


以下是代码。我已经多次查看文档,但我返回的是 Result<>,所以不确定哪里有问题。
use std::sync::Arc;


#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Hello, world!");

    use reqwest::{cookie::Jar, Url};
    use reqwest::header;

    let mut headers = header::HeaderMap::new();
    headers.insert("User-Agent", header::HeaderValue::from_static("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"));
    headers.insert("Content-Type", header::HeaderValue::from_static("application/json"));
    
    let cookie = "cookies";

    let jar = Jar::default();
    let cookie_url = "https://url.com/".parse::<Url>()?;
    jar.add_cookie_str(cookie, &cookie_url);

    let body = String::from("post body"); 

    let client = reqwest::Client::builder()
    .default_headers(headers)
    .cookie_store(true)
    .cookie_provider(Arc::new(jar))
    .build()?;

    let path = "https://long_url.com".parse::<Url>()?;

    let res = client
        .post(path)
        .body(body)
        .send()
        .await?;

    let text = res.text().await?;
    println!("{}", text);

    Ok(());
}

谢谢!


你的 main 函数末尾有一个多余的分号。 - Jmb
2个回答

11

由于执行的转换可能会导致信息有些混乱,您可能希望将此报告给错误跟踪器,但请注意措辞:

^ 无法在返回 ()异步块中使用 ? 运算符

它使用了单词“块”,而不是“函数”。因为这实际上是一个级联错误:在幕后,一个async 函数被转换为一个状态机,其中每个await 是代码块之间的“yield点”,所以

let res = client
        .post(path)
        .body(body)
        .send()
        .await?;

    let text = res.text().await?;
    println!("{}", text);

    Ok(());

可以这样理解(这不是实际的转换过程,如果您想了解实际的分解过程,Jon Gjengset在该主题上有一段详细的视频)

let future = async {
    client.post(path).body(body).send()
};
yield future;
let future = async {
    let res = future.value()?;
    res.text()
};
yield future;
let future = async {
    let text = future.value()?;
    println!("{}", text);

    Ok(());
};
return future;

请注意最后一个代码块的最后一行表达式:Ok(());。这里是问题所在:
分号会“屏蔽”表达式的正常值,并导致返回()而不是Result<...>,因此出现了类型不兼容的错误,你看到的是该代码块的返回值不一致。
在所有异步代码块的错误堆栈末尾,编译器实际上显示了“源”错误:
error[E0308]: mismatched types
 --> src/main.rs:6:20
  |
6 | async fn main() -> Result<(), Box<dyn std::error::Error>> {
  |          ----      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
  |          |
  |          implicitly returns `()` as its body has no tail or `return` expression
  |
  = note:   expected enum `Result<(), Box<(dyn std::error::Error + 'static)>>`
          found unit type `()`

如果您查看整个“异步块”错误,它会特别指出每次出错的Ok(());代码:

error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
   --> src/lib.rs:19:55
    |
6   |   async fn main() -> Result<(), Box<dyn std::error::Error>> {
    |  ___________________________________________________________-
7   | |     println!("Hello, world!");
8   | |
9   | |     use reqwest::{cookie::Jar, Url};
...   |
19  | |     let cookie_url = "https://url.com/".parse::<Url>()?;
    | |                                                       ^ cannot use the `?` operator in an async block that returns `()`
...   |
41  | |     Ok(());
42  | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
    = help: the trait `FromResidual<Result<Infallible, url::parser::ParseError>>` is not implemented for `()`
note: required by `from_residual`

1
Ok(()) 是一个 Result<(), ...>。问题在于 main 函数末尾多了一个分号。 - Jmb
是的,那就是我的意思,但确实不太清楚。我会编辑相关部分。 - Masklinn
谢谢!我永远也想不到这个。 - MB.

2

当我在playground上尝试您的代码时,我会像您一样遇到很多错误,但我还会遇到这个错误:

error[E0308]: mismatched types
 --> src/main.rs:5:20
  |
5 | async fn main() -> Result<(), Box<dyn std::error::Error>> {
  |          ----      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `()`
  |          |
  |          implicitly returns `()` as its body has no tail or `return` expression
  |
  = note:   expected enum `Result<(), Box<(dyn std::error::Error + 'static)>>`
          found unit type `()`

这是由于您的main函数末尾多了一个分号导致的。删除这个分号可以修复所有错误:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Hello, world!");

    use reqwest::{cookie::Jar, Url};
    use reqwest::header;

    let mut headers = header::HeaderMap::new();
    headers.insert("User-Agent", header::HeaderValue::from_static("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"));
    headers.insert("Content-Type", header::HeaderValue::from_static("application/json"));
    
    let cookie = "cookies";

    let jar = Jar::default();
    let cookie_url = "https://url.com/".parse::<Url>()?;
    jar.add_cookie_str(cookie, &cookie_url);

    let body = String::from("post body"); 

    let client = reqwest::Client::builder()
    .default_headers(headers)
    .cookie_store(true)
    .cookie_provider(Arc::new(jar))
    .build()?;

    let path = "https://long_url.com".parse::<Url>()?;

    let res = client
        .post(path)
        .body(body)
        .send()
        .await?;

    let text = res.text().await?;
    println!("{}", text);

    Ok(())
}

Playground


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接