我如何有条件地退回不同类型的期货?

Dom*_*kis 13 asynchronous future control-flow rust

我有一个方法,根据谓词,将返回一个未来或另一个.换句话说,返回未来的if-else表达式:

extern crate futures; // 0.1.23

use futures::{future, Future};

fn f() -> impl Future<Item = usize, Error = ()> {
    if 1 > 0 {
        future::ok(2).map(|x| x)
    } else {
        future::ok(10).and_then(|x| future::ok(x + 2))
    }
}
Run Code Online (Sandbox Code Playgroud)

这不编译:

error[E0308]: if and else have incompatible types
  --> src/lib.rs:6:5
   |
6  | /     if 1 > 0 {
7  | |         future::ok(2).map(|x| x)
8  | |     } else {
9  | |         future::ok(10).and_then(|x| future::ok(x + 2))
10 | |     }
   | |_____^ expected struct `futures::Map`, found struct `futures::AndThen`
   |
   = note: expected type `futures::Map<futures::FutureResult<{integer}, _>, [closure@src/lib.rs:7:27: 7:32]>`
              found type `futures::AndThen<futures::FutureResult<{integer}, _>, futures::FutureResult<{integer}, _>, [closure@src/lib.rs:9:33: 9:54]>`
Run Code Online (Sandbox Code Playgroud)

期货的创建方式不同,可能会持有闭包,因此它们的类型并不相同.理想情况下,解决方案不会使用Boxes,因为我的异步逻辑的其余部分不使用它们.

期货中的if-else逻辑通常如何?

She*_*ter 19

Either

使用futures::future::Either没有额外的堆分配:

extern crate futures; // 0.1.23

use futures::{
    future::{self, Either},
    Future,
};

fn f() -> impl Future<Item = usize, Error = ()> {
    if 1 > 0 {
        Either::A(future::ok(2).map(|x| x))
    } else {
        Either::B(future::ok(10).and_then(|x| future::ok(x + 2)))
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这需要固定的堆栈分配.如果A占用1个字节并且99%的时间发生,但B占用512个字节,Either总是占用512个字节(加上一些).这并不总是一场胜利.

盒装特质对象

extern crate futures; // 0.1.23

use futures::{future, Future};

fn f() -> Box<Future<Item = usize, Error = ()>> {
    if 1 > 0 {
        Box::new(future::ok(2).map(|x| x))
    } else {
        Box::new(future::ok(10).and_then(|x| future::ok(x + 2)))
    }
}
Run Code Online (Sandbox Code Playgroud)

正如Matthieu M.指出的那样,这两种解决方案可以结合起来:

我会注意到,对于大型的情况,有一个中间解决方案B:Either(A, Box<B>).这样,您只需在极少数情况下支付堆分配B

请注意,Either如果您有两个以上的条件(Either<A, Either<B, C>>; Either<Either<A, B>, Either<C, D>>等等),您也可以堆叠s :

也可以看看:

  • 我会注意到,对于大型"B"的情况,存在一个中间解决方案:"要么(A,Box <B>)".这样,你只需要在罕见的情况下支付堆分配,它就是B. (4认同)