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

我有一个方法,根据谓词的不同,它会返回一个将来或另一个。换句话说,一个if-else表达式返回一个future:


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))

    }

}

这不会编译:


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]>`

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


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


牧羊人nacy
浏览 406回答 1
1回答

蓝山帝景

Either使用futures::future::Either没有额外的堆分配:extern crate futures; // 0.1.23use futures::{&nbsp; &nbsp; future::{self, Either},&nbsp; &nbsp; Future,};fn f() -> impl Future<Item = usize, Error = ()> {&nbsp; &nbsp; if 1 > 0 {&nbsp; &nbsp; &nbsp; &nbsp; Either::A(future::ok(2).map(|x| x))&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; Either::B(future::ok(10).and_then(|x| future::ok(x + 2)))&nbsp; &nbsp; }}但是,这需要固定的堆栈分配。如果A占用1个字节并在99%的时间内发生,但B占用512个字节,则您Either将始终占用512个字节(加上一些字节)。这并不总是胜利。装箱特征对象extern crate futures; // 0.1.23use futures::{future, Future};fn f() -> Box<Future<Item = usize, Error = ()>> {&nbsp; &nbsp; if 1 > 0 {&nbsp; &nbsp; &nbsp; &nbsp; Box::new(future::ok(2).map(|x| x))&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; Box::new(future::ok(10).and_then(|x| future::ok(x + 2)))&nbsp; &nbsp; }}正如Matthieu M.指出的那样,可以将两种解决方案结合起来:我会注意到对于大的情况有一个中间的解决方案B:Either(A, Box<B>)。这样,您仅需在极少数情况下为堆分配付费B请注意,Either如果您有两个以上的条件(Either<A, Either<B, C>>; Either<Either<A, B>, Either<C, D>>等),也可以堆叠s :fn f(v: i32) -> impl Future<Item = i32, Error = ()> {&nbsp; &nbsp; use std::cmp::Ordering;&nbsp; &nbsp; match v.cmp(&0) {&nbsp; &nbsp; &nbsp; &nbsp; Ordering::Less => Either::A(future::ok(2).map(|x| -x)),&nbsp; &nbsp; &nbsp; &nbsp; Ordering::Equal => Either::B(Either::A(future::ok(0))),&nbsp; &nbsp; &nbsp; &nbsp; Ordering::Greater => Either::B(Either::B(future::ok(-2).map(|x| x * x))),&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP