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框架的宏会对函数进行包装生成路由处理逻辑,如果宏的实现没有考虑异步函数的场景,就会出现这种问题。
解决办法
查看宏展开代码定位问题
使用cargo expand命令查看宏展开后的具体代码,确认原函数的async属性是否被移除:cargo expand --package 你的包名 src/image.rs展开后如果看到生成的外层函数是同步的,就坐实了宏的问题。
检查宏的参数配置
大部分支持异步函数的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 { // ... 原函数代码 }具体参数名可以参考该宏所属框架的文档。
修改宏定义(如果有权限)
如果你能修改api_operation宏的实现,需要确保宏在生成包装代码时保留async关键字。比如在宏展开时,把原函数的async修饰符传递到生成的外层函数中。临时应急方案(不推荐长期使用)
如果暂时无法调整宏,可尝试将await调用包裹在async块中并再次await,但这只是绕过问题,不是根本解决办法:let upload_status = async { files::save_file(payload, format!("{upload_dir}/test.png").to_string()).await }.await;
内容的提问来源于stack exchange,提问作者munHunger
相关产品推荐
相关产品推荐

