Условно связать будущее Rust на основе первоначального будущего результата? - PullRequest
0 голосов
/ 02 ноября 2018

Если у меня есть какое-то будущее, которое я объединяю в цепочки, как я могу сделать второе связанное будущее зависимым от результата первого будущего?

Для надуманного примера у меня есть что-то вроде:

extern crate futures;
extern crate tokio_core;

use futures::{future, Future};
use tokio_core::reactor::Core;

fn add_one(x: i64) -> impl Future<Item = i64, Error = ()> {
    future::ok(x).map(|x| x + 1)
}

fn double(x: i64) -> impl Future<Item = i64, Error = ()> {
    future::ok(x).map(|x| x * 2)
}

fn add_one_then_double(x: i64) -> impl Future<Item = i64, Error = ()> {
    future::ok(x).and_then(add_one).and_then(double)
}

fn main() {
    let mut reactor = Core::new().unwrap();
    println!("{:?}", reactor.run(add_one_then_double(10)).unwrap());
}

Как я могу затем изменить будущее add_one_then_double, чтобы оно зависело от результата будущего add_one, например ::10000 *

fn add_one_then_double_if_positive(x: i64) -> impl Future<Item = i64, Error = ()> {
    future::ok(x).and_then(add_one).map(|v| {
        if v >= 0 {
            // chain the `double` future
        } else {
            // return `v` as the result
        }
    })
}

1 Ответ

0 голосов
/ 02 ноября 2018

Если вы хотите связать другое будущее, вам нужно использовать комбинатор будущего and_then(), а не map(). Этот комбинатор ожидает другое будущее в качестве возвращаемого значения, поэтому обе ветви вашего оператора if должны давать будущее. В первой ветке вы хотите связать double(v), что уже есть будущее. Во второй ветви вы хотите передать значение без изменений, поэтому вам нужно превратить его в будущее, которое немедленно преобразуется в v с использованием future::ok(). Так как double(v) и future::ok(v) имеют разные типы, вам нужно либо использовать future::Either, либо пометить фьючерсами. Вот один из вариантов:

fn add_one_then_double(x: i64) -> impl Future<Item=i64, Error=()> {
    future::ok(x)
        .and_then(add_one)
        .and_then(|v| {
            if v >= 0 {
                future::Either::A(double(v))
            } else {
                future::Either::B(future::ok(v))
            }
        })
}

Детская площадка

...