为何含内部异步调用的Axum通用路由无法编译?
通用Axum API路由适配自定义Handler的编译错误解决
我正在构建一个通用Axum API,想要让路由适配任意自定义Handler实现,但代码编译失败,报错信息如下:
原代码
use std::marker::PhantomData; use std::sync::Arc; use axum::extract::State; use axum::Router; use axum::routing::get; use tokio::sync::Mutex; trait Handler{ async fn handle(&mut self); } struct GenericRouter<Backend, Handler>{ _marker: PhantomData<(Backend, Handler)> } struct AxumBackend; impl<H> GenericRouter<AxumBackend, H> where H: Handler + Send + 'static, { async fn route(state: State<Arc<Mutex<H>>>) { let mut state = state.lock().await; state.handle().await; } fn build(&self, handler: H) -> Router { let shared_state = Arc::new(Mutex::new(handler)); Router::new() .route("/", get(Self::route)) .with_state(shared_state) } }
编译错误
error[E0277]: the trait bound `fn(axum::extract::State<Arc<tokio::sync::Mutex<H>>>) -> impl Future<Output = ()> {GenericRouter::<reproducable_example::AxumBackend, H>::route}: axum::handler::Handler<_, _>` is not satisfied --> src/reproducable_example.rs:34:29 | 34 | .route("/", get(Self::route)) | --- ^^^^^^^^^^^ the trait `axum::handler::Handler<_, _>` is not implemented for fn item `fn(State<Arc<Mutex<H>>>) -> impl Future<Output = ()> {GenericRouter::<AxumBackend, H>::route}` | | | required by a bound introduced by this call | = help: the following other types implement trait `axum::handler::Handler<T, S>`: `Layered<L, H, T, S>` implements `axum::handler::Handler<T, S>` `MethodRouter<S>` implements `axum::handler::Handler<(), S>` note: required by a bound in `axum::routing::get` | 385 | top_level_handler_fn!(get, GET); | ^^^^^^^^^^^^^^^^^^^^^^---^^^^^^ | | | | | required by a bound in this function | required by this bound in `get` = note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
注释掉state.handle().await;代码后即可正常编译,说明问题不在函数签名或trait绑定上。
问题原因
Axum的Handler trait要求handler函数返回的future必须满足Send约束(Axum会在多线程运行时调度这些future)。而自定义的Handler trait中,async fn handle(&mut self)返回的future默认没有Send标注,导致调用state.handle().await后,整个route函数返回的future不满足Send,进而无法实现Axum的Handler trait。
解决方案
给自定义Handler trait的handle方法返回的future加上Send约束,确保所有实现该trait的类型返回的future都是可发送的。
修改后的代码:
use std::marker::PhantomData; use std::sync::Arc; use axum::extract::State; use axum::Router; use axum::routing::get; use tokio::sync::Mutex; // 导入Future trait以标注约束 use std::future::Future; trait Handler{ // 为返回的Future添加Send约束 fn handle(&mut self) -> impl Future<Output = ()> + Send; } struct GenericRouter<Backend, Handler>{ _marker: PhantomData<(Backend, Handler)> } struct AxumBackend; impl<H> GenericRouter<AxumBackend, H> where H: Handler + Send + 'static, { async fn route(state: State<Arc<Mutex<H>>>) { let mut state = state.lock().await; state.handle().await; } fn build(&self, handler: H) -> Router { let shared_state = Arc::new(Mutex::new(handler)); Router::new() .route("/", get(Self::route)) .with_state(shared_state) } }
说明
通过显式标注impl Future<Output = ()> + Send,强制所有Handler实现的handle方法返回可发送的future,这样route函数返回的future就满足了Axum对Handler trait的要求,编译即可通过。
内容的提问来源于stack exchange,提问作者Furkan Guvenc
相关产品推荐
相关产品推荐

