Rust中能否引用匿名类型作为结构体成员?
解答
当前稳定版Rust确实无法直接引用async块生成的匿名future类型来定义结构体成员,但有两种无额外开销的解决方案,同时未来Rust也有相关特性正在推进以简化这类场景。
方案一:使用Nightly特性type_alias_impl_trait
Rust的nightly分支提供了type_alias_impl_trait特性,允许我们为impl Trait类型定义别名,之后就可以在结构体中使用这个别名。这种方式最简洁,和原代码逻辑几乎一致:
#![feature(type_alias_impl_trait)] use std::future::Future; use std::pin::Pin; // 为wrap_future返回的impl Future类型定义别名 type WrappedFuture = impl Future<Output = ()>; struct MyStruct { myvec: Vec<WrappedFuture>, } fn wrap_future(a: Pin<Box<dyn Future<Output = ()>>>) -> WrappedFuture { async { println!("doing stuff before awaiting"); let result = a.await; println!("doing stuff after awaiting"); result } } fn main() { let mut v: Vec<WrappedFuture> = Vec::new(); for _ in 1..10 { v.push(wrap_future(Box::pin(async {}))); } let thing = MyStruct { myvec: v }; }
注意这个特性目前仅在nightly工具链可用,尚未稳定,但已经处于推进稳定的阶段。
方案二:手动实现Future结构体
如果你必须使用稳定版Rust,可以手动模拟编译器生成的匿名future类型——自定义一个结构体并实现Future trait,完全复刻原async块的逻辑。这种方式零开销,但需要手写poll逻辑,代码量会增加:
use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; // 自定义WrappedFuture结构体,包含内部future和执行状态 struct WrappedFuture<T> { state: State<T>, } // 标记future的执行阶段 enum State<T> { BeforeAwait(Pin<Box<dyn Future<Output = T>>>), AwaitingInner(Pin<Box<dyn Future<Output = T>>>), Done, } impl<T> Future for WrappedFuture<T> { type Output = T; fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { loop { match &mut self.state { State::BeforeAwait(inner) => { println!("doing stuff before awaiting"); // 转移内部future所有权,切换到等待状态 let inner = std::mem::take(inner); self.state = State::AwaitingInner(inner); } State::AwaitingInner(inner) => { match inner.as_mut().poll(cx) { Poll::Ready(result) => { println!("doing stuff after awaiting"); self.state = State::Done; return Poll::Ready(result); } Poll::Pending => return Poll::Pending, } } State::Done => unreachable!("Future should not be polled after completion"), } } } } struct MyStruct<T> { myvec: Vec<WrappedFuture<T>>, } fn wrap_future<T>(a: Pin<Box<dyn Future<Output = T>>>) -> WrappedFuture<T> { WrappedFuture { state: State::BeforeAwait(a), } } fn main() { let mut v: Vec<WrappedFuture<()>> = Vec::new(); for _ in 1..10 { v.push(wrap_future(Box::pin(async {}))); } let thing = MyStruct { myvec: v }; }
未来Rust的支持前景
type_alias_impl_trait特性正在进行稳定化工作,预计未来会进入稳定版Rust,届时可以直接用类型别名的方式解决问题。- 社区还在讨论允许在结构体字段中直接使用
impl Trait的提案,不过目前仍处于早期设计阶段。
总之,你想要的无装箱实现目前在nightly下已经可以轻松做到,稳定版也有手动实现的方案,未来Rust会提供更原生的支持。
内容的提问来源于stack exchange,提问作者wallefan
相关产品推荐
相关产品推荐

