期货-rs使用'BoxStream'上的Stream组合器

时间:2017-01-21 21:39:57

标签: rust future

使用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的结构会以某种方式解决问题吗?

1 个答案:

答案 0 :(得分:0)

正如@FrancisGagné在评论中指出的那样,futures-rsimpl<S: ?Sized + Stream> Stream for Box<S>模块中声明了futures::Stream。在我的代码所在的测试中,我无法导入Stream,因此特征不在范围内。

编译器没有因缺少wait()函数而触发错误,因为它首先出现了未标注的问题。

通过将use futures::Stream;添加到函数的开头来解决此问题。