You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中标记async的函数为何无法使用await?编译报错E0728求解

加了#[api_operation]宏的async函数无法使用await的问题分析与解决

问题代码

#[api_operation(
    tag = "image",
    summary = "uploads an image",
    description = r###"upload an image to an account"###,
    error_code = 405
)]
pub async fn upload_image(mut payload: Multipart) -> impl Responder {
    let upload_dir = std::env::var("UPLOAD_DIR").unwrap_or_else(|_| "./uploads".to_string());

    let upload_status = files::save_file(payload, format!("{upload_dir}/test.png").to_string()).await;
}

编译错误

error[E0728]: `await` is only allowed inside `async` functions and blocks
  --> src/image.rs:18:97
   |
9  | / #[api_operation(
10 | |     tag = "image",
11 | |     summary = "uploads an image",
12 | |     description = r###"upload an image to an account"###,
13 | |     error_code = 405
14 | | )]
   | |__- this is not `async`
...
18 |       let upload_status = files::save_file(payload, format!("{upload_dir}/test.png").to_string()).await;
   |                                                                                                   ^^^^^ only allowed inside `async` functions and blocks

原因分析

你的猜测是对的——#[api_operation]宏在展开过程中,没有正确保留原函数的async修饰符,或者生成了一个非异步的包装函数,把原async函数的上下文替换成了非异步环境,导致内部的await调用违反了Rust的语法规则。

很多API框架的宏会对函数进行包装生成路由处理逻辑,如果宏的实现没有考虑异步函数的场景,就会出现这种问题。

解决办法

  1. 查看宏展开代码定位问题
    使用cargo expand命令查看宏展开后的具体代码,确认原函数的async属性是否被移除:

    cargo expand --package 你的包名 src/image.rs
    

    展开后如果看到生成的外层函数是同步的,就坐实了宏的问题。

  2. 检查宏的参数配置
    大部分支持异步函数的API宏会提供显式声明异步的参数,比如添加async = true到宏参数中:

    #[api_operation(
        tag = "image",
        summary = "uploads an image",
        description = r###"upload an image to an account"###,
        error_code = 405,
        async = true
    )]
    pub async fn upload_image(mut payload: Multipart) -> impl Responder {
        // ... 原函数代码
    }
    

    具体参数名可以参考该宏所属框架的文档。

  3. 修改宏定义(如果有权限)
    如果你能修改api_operation宏的实现,需要确保宏在生成包装代码时保留async关键字。比如在宏展开时,把原函数的async修饰符传递到生成的外层函数中。

  4. 临时应急方案(不推荐长期使用)
    如果暂时无法调整宏,可尝试将await调用包裹在async块中并再次await,但这只是绕过问题,不是根本解决办法:

    let upload_status = async {
        files::save_file(payload, format!("{upload_dir}/test.png").to_string()).await
    }.await;
    

内容的提问来源于stack exchange,提问作者munHunger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:52:44