Rust异步trait实现泛型不足编译错误原因排查
Rust编译错误分析:
AppWrapper实现不够通用的本质原因 问题重现
以下代码编译失败:
use std::marker::PhantomData; use async_trait::async_trait; #[async_trait(?Send)] trait App { async fn call_app<'req>(&self, req: &'req str); } #[async_trait(?Send)] trait AppWrapper<'req> { async fn wrapped_call(&self, req: &'req str); } #[async_trait(?Send)] trait Handle<'req> { async fn handle_call(&self, req: &'req [u8]); } #[async_trait(?Send)] impl<'req, F> Handle<'req> for F where F: Fn(&'req [u8]), { async fn handle_call(&self, req: &'req [u8]) { self(req) } } struct IntoApp<'req, H: Handle<'req>> { handle: H, _marker: PhantomData<&'req ()>, } impl<'req, H: Handle<'req>> IntoApp<'req, H> { fn new(handle: H) -> Self { Self { handle, _marker: PhantomData, } } } #[async_trait(?Send)] impl<'req, H: Handle<'req>> AppWrapper<'req> for IntoApp<'req, H> { async fn wrapped_call(&self, req: &'req str) { self.handle.handle_call(req.as_bytes()).await; } } #[async_trait(?Send)] impl<T> App for T where T: for<'req> AppWrapper<'req>, { async fn call_app<'req>(&self, req: &'req str) { self.wrapped_call(req).await } } fn test(s: &[u8]) {} fn run() { let boxed: Box<dyn App> = Box::new(IntoApp::new(test)); // error }
编译错误信息:
error: implementation of `test::AppWrapper` is not general enough --> src/app/test.rs:76:31 | 76 | let boxed: Box<dyn App> = Box::new(app); | ^^^^^^^^^^^^^ implementation of `test::AppWrapper` is not general enough | = note: `test::AppWrapper<'0>` would have to be implemented for the type `test::IntoApp<'_, for<'r> fn(&'r [u8]) {test::test}>`, for any lifetime `'0`... = note: ...but `test::AppWrapper<'1>` is actually implemented for the type `test::IntoApp<'1, for<'r> fn(&'r [u8]) {test::test}>`, for some specific lifetime `'1`
移除IntoApp结构体,直接为Handle实现AppWrapper后代码可正常编译:
use async_trait::async_trait; #[async_trait(?Send)] trait App { async fn call_app<'req>(&self, req: &'req str); } #[async_trait(?Send)] trait AppWrapper<'req> { async fn wrapped_call(&self, req: &'req str); } #[async_trait(?Send)] trait Handle<'req> { async fn handle_call(&self, req: &'req [u8]); } #[async_trait(?Send)] impl<'req, F> Handle<'req> for F where F: Fn(&'req [u8]), { async fn handle_call(&self, req: &'req [u8]) { self(req) } } #[async_trait(?Send)] impl<'req, H: Handle<'req>> AppWrapper<'req> for H { async fn wrapped_call(&self, req: &'req str) { self.handle_call(req.as_bytes()).await; } } #[async_trait(?Send)] impl<T> App for T where T: for<'req> AppWrapper<'req>, { async fn call_app<'req>(&self, req: &'req str) { self.wrapped_call(req).await } } fn test(s: &[u8]) {} fn run() { let boxed: Box<dyn App> = Box::new(test); }
错误本质原因
核心问题在于生命周期的绑定范围不匹配:
Apptrait 的实现要求类型T满足for<'req> AppWrapper<'req>,意思是这个类型必须对**任意生命周期'req**都实现了AppWrapper<'req>。- 而
IntoApp<'req, H>结构体本身把生命周期'req作为自身的泛型参数,它的AppWrapper<'req>实现是绑定到自身的'req参数的——也就是说,一个IntoApp<'a, H>实例只能实现AppWrapper<'a>,无法做到对任意'req都实现AppWrapper<'req>。 - 当你创建
IntoApp::new(test)时,test是一个for<'r> fn(&'r [u8])类型(对任意生命周期都有效的函数),但IntoApp会把它绑定到某个具体的'req上,导致最终的IntoApp实例只能满足某个特定生命周期的AppWrapper,不符合App要求的“任意生命周期”约束。
两种实现的差异
带IntoApp的实现
IntoApp结构体的泛型参数'req把自身和某个特定生命周期绑定死了,它的AppWrapper实现只能对应这个特定的'req。即使传入的H(比如test函数)本身能支持所有生命周期,IntoApp的结构也限制了它只能为一个固定生命周期实现AppWrapper,无法满足for<'req> AppWrapper<'req>的约束。
直接为Handle实现AppWrapper的实现
这里的AppWrapper<'req>实现是针对任意满足Handle<'req>的H,而test函数作为for<'r> fn(&'r [u8]),它对**任意生命周期'req**都实现了Handle<'req>(因为函数的泛型生命周期满足所有情况)。因此test本身就满足for<'req> AppWrapper<'req>,自然能适配App trait 的约束,顺利装箱为Box<dyn App>。
内容的提问来源于stack exchange,提问作者Lexo
相关产品推荐
相关产品推荐

