使用futures-rs
库,我遇到了一种情况,在返回给用户之前,需要通过不确定数量的其他流映射流。由于输出流的确切类型在此操作结束时是未知的,所以我一直在使用BoxStream
特征对象,同时将流存储在结构中并返回时。
虽然这种方法很好,但它有一个令人遗憾的副作用,即导致内部Stream
对象无法使用。这是一个问题,因为<{>> stream combinators的每个在签名中都需要Self: Sized
,这意味着我甚至无法wait()
返回BoxStream
为了将其转换为阻塞迭代器。
以下是可能导致此问题的情况示例:
struct Server {
receiver: Option<Box<Stream<Item = usize, Error = ()> + Send>>,
}
impl Server {
pub fn new() -> Server {
let (tx, rx) = channel(0);
// do things with the tx (subscribe to tcp socket, connect to database, etc.)
Server { receiver: Some(rx.boxed()) }
}
/// Maps the inner `Receiver` through another stream, essentially duplicating it.
pub fn get_stream(&mut self) -> Result<Box<Stream<Item = usize, Error = ()> + Send>, ()> {
let (tx, rx) = channel(0);
let strm = self.receiver.take().unwrap();
let mut tx_opt = Some(tx);
let new_strm = strm.map(move |msg| {
// unfortunate workaround needed since `send()` takes `self`
let mut tx = tx_opt.take().unwrap();
tx = tx.send(msg.clone()).wait().unwrap();
tx_opt = Some(tx);
msg
});
simbroker.receiver = Some(new_strm.boxed());
Ok(rx.boxed())
}
}
pub fn main() {
let server = Server::new();
// possible that this may happen 0..n times
let rx: BoxStream<usize, ()> = server.get_stream();
// can't do this since the inner `Stream` trait object isn't `Sized` and `wait()`
// (along with all other stream combinators) requires that in their signatures.
for msg in rx.wait() {
// compiler error here
// ...
}
}
如上面的代码所示,BoxStream
是必要的,因为在流上调用map()
会将其类型从Receiver
更改为Map
,这将导致无法存储回到结构中。使用返回的BoxStream
几乎不可能做任何事情,因为它是?Sized
。实际上,可用于特征对象Stream
的仅函数是poll()
,它应该永远不会在Task
之外调用。
有没有什么方法可以避免这个问题,而不会像返回包含可能发生的任何一种可能的流类型的枚举?编写我自己的实现Stream
的结构会以某种方式解决问题吗?
答案 0 :(得分:0)
正如@FrancisGagné在评论中指出的那样,futures-rs
在impl<S: ?Sized + Stream> Stream for Box<S>
模块中声明了futures::Stream
。在我的代码所在的测试中,我无法导入Stream
,因此特征不在范围内。
编译器没有因缺少wait()
函数而触发错误,因为它首先出现了未标注的问题。
通过将use futures::Stream;
添加到函数的开头来解决此问题。