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

我有一种方法,根据谓词的不同,它会返回一个将来或另一个。换句话说,一个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逻辑通常如何完成?


红糖糍粑
浏览 567回答 3
3回答

白衣染霜花

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; }}

开满天机

r我试图说Either<Either<A, B>, C>可以写成Either<Either<A, B>, Either<C, Empty<_, _>>>。但是现在我不确定是否会更好。两种类型都同样嵌套,但这似乎不是优势。我想我太复杂了

MMTTMM

我给出了3个(奇数)和4个(偶数)条件的示例:如果您有2个以上的条件(Either<A, Either<B, C>>;&nbsp;Either<Either<A, B>, Either<C, D>>等)。我不明白你为什么用Empty。
打开App,查看更多内容
随时随地看视频慕课网APP