无法在mpsc :: channel上使用Stream :: take_while:bool:不满足未来

时间:2019-01-17 19:11:15

标签: rust future rust-tokio

我想在一个线程中运行一个事件循环,并处理来自UDP套接字的数据,直到另一个线程发出停止工作的信号。

这对我来说是一项艰巨的任务,因此我想从一个简单的任务开始: 一个线程启动事件循环并等待另一个线程发出结束信号:

use futures::{future, future::Future, stream::Stream, sync::mpsc};
use std::{io, io::BufRead, thread};

fn main() {
    let (mut tx, rx) = mpsc::channel::<bool>(1);

    let thr = thread::spawn(|| {
        let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
        runtime.spawn(
            future::lazy(|| {
                println!("event loop started");
                Ok(())
            })
            .and_then(rx.take_while(|x| *x == true).into_future()),
        );

        runtime.run()
    });

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        println!("{}", line);
        if line == "exit" {
            tx.try_send(false).unwrap();
            break;
        }
    }
    thr.join().unwrap().unwrap();
}

此代码无法编译:

error[E0277]: the trait bound `bool: futures::future::Future` is not satisfied
  --> src/main.rs:14:26
   |
14 |             .and_then(rx.take_while(|x| *x == true).into_future()),
   |                          ^^^^^^^^^^ the trait `futures::future::Future` is not implemented for `bool`
   |
   = note: required because of the requirements on the impl of `futures::future::IntoFuture` for `bool`

error[E0599]: no method named `into_future` found for type `futures::stream::take_while::TakeWhile<futures::sync::mpsc::Receiver<bool>, [closure@src/main.rs:14:37: 14:51], bool>` in the current scope
  --> src/main.rs:14:53
   |
14 |             .and_then(rx.take_while(|x| *x == true).into_future()),
   |                                                     ^^^^^^^^^^^
   |
   = note: the method `into_future` exists but the following trait bounds were not satisfied:
           `futures::stream::take_while::TakeWhile<futures::sync::mpsc::Receiver<bool>, [closure@src/main.rs:14:37: 14:51], bool> : futures::stream::Stream`
           `&mut futures::stream::take_while::TakeWhile<futures::sync::mpsc::Receiver<bool>, [closure@src/main.rs:14:37: 14:51], bool> : futures::stream::Stream`

如何解决编译错误?

1 个答案:

答案 0 :(得分:0)

阅读并了解您尝试使用的方法的文档和功能签名:

fn take_while<P, R>(self, pred: P) -> TakeWhile<Self, P, R>
where
    P: FnMut(&Self::Item) -> R,
    R: IntoFuture<Item = bool, Error = Self::Error>,
    Self: Sized, 

take_while使用闭包,该闭包返回必须转换为将来的某些类型; bool不可转换为未来。最简单的方法是通过future::ok

let thr = thread::spawn(|| {
    let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
    runtime.spawn({
        rx.take_while(|&x| future::ok(x))
            .for_each(|x| {
                println!("{}", x);
                future::ok(())
            })
    });

    runtime.run()
});

另请参阅:

  

但是我的问题还在于加入future::lazyrx.take_while

与您要问的问题无关。再次,我们来看一下Future::and_then的文档:

fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
where
    F: FnOnce(Self::Item) -> B,
    B: IntoFuture<Error = Self::Error>,
    Self: Sized, 

类似于take_while,它需要一个闭包,并且闭包必须返回可以转换为将来的内容。您的代码未提供闭包。

然后查看Stream::into_future。这将返回a type that implements Future并返回一个元组。元组中的第一项是流中的单个值,第二项是流本身,以允许获取更多值。

为了使所有项目和错误类型正确无误,我自由使用了map(drop)map_err(drop) —您将希望为数据和错误处理做得更好。

runtime.spawn({
    future::lazy(|| {
        println!("event loop started");
        Ok(())
    })
    .and_then(|_| {
        rx.take_while(|&x| future::ok(x))
            .into_future()
            .map(drop)
            .map_err(drop)
    })
    .map(drop)
});

真的,您应该只使用oneshot channel;简单得多:

use futures::{
    future::{self, Future},
    sync::oneshot,
};
use std::thread;

fn main() {
    let (tx, rx) = oneshot::channel();

    let thr = thread::spawn(|| {
        let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();

        runtime.spawn({
            future::lazy(|| {
                println!("event loop started");
                Ok(())
            })
            .and_then(|_| rx.map_err(drop))
        });

        runtime.run()
    });

    let lines = ["hello", "goodbye", "exit"];
    for &line in &lines {
        if line == "exit" {
            tx.send(()).unwrap();
            break;
        }
    }

    thr.join().unwrap().unwrap();
}