如何封装动态类型Stream简化API调用,减少代码中dynamic关键字冗余
解决方案
你的核心需求是封装BoxStream<Row>为自定义结构体,避免代码中到处出现动态分发流的类型标注,poll_next方法只需要将调用转发给内部的stream字段即可,同时需要修正你现有代码中的生命周期不匹配问题。
修正后的完整可编译代码
use std::pin::Pin; use std::task::{Context, Poll}; use futures::prelude::stream::BoxStream; use futures::Stream; pub struct Row; pub struct RowCollection<'a> { stream: BoxStream<'a, Row>, } // 修正生命周期标注,对齐内部流和结构体的生命周期 impl<'a> RowCollection<'a> { pub fn new(stream: BoxStream<'a, Row>) -> Self { RowCollection { stream } } } impl Stream for RowCollection<'_> { type Item = Row; fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { // 直接转发poll_next调用到内部的BoxStream Pin::as_mut(&mut self.get_mut().stream).poll_next(cx) } }
原理解释
BoxStream<'a, T>是futures库预置的类型别名,等价于Pin<Box<dyn Stream<Item = T> + Send + 'a>>,正好用来封装动态分发的堆上流,符合你减少代码中dyn关键字散落的需求。- 因为
RowCollection只是做了一层薄封装没有自定义流逻辑,所以poll_next直接转发内部流的调用即可。 - 关于Pin投影:
RowCollection没有自定义的Pin不变量,且内部stream字段本身是Unpin类型(Pin<Box<T>>始终实现Unpin),所以可以安全调用self.get_mut()拿到结构体的可变引用,再获取内部stream的可变引用,最后通过Pin::as_mut转为符合poll_next方法要求的Pin包装引用即可。
扩展说明
如果后续你需要给RowCollection添加额外的辅助方法,直接在impl<'a> RowCollection<'a>块中添加即可,上层使用时只需要接触RowCollection类型,不需要再感知内部的BoxStream和dyn关键字。
内容的提问来源于stack exchange,提问作者eltiare
相关产品推荐
相关产品推荐

