我有一个方法,根据谓词的不同,它会返回一个将来或另一个。换句话说,一个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]>`

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

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

最佳答案

使用async/await
从Rust 1.39开始,您可以使用asyncawait语法来涵盖大多数情况:

async fn a() -> usize {
    2
}
async fn b() -> usize {
    10
}

async fn f() -> usize {
    if 1 > 0 {
        a().await
    } else {
        b().await + 2
    }
}

也可以看看:
  • What is the purpose of async/await in Rust?
  • Either
    通过 futures::future::Either 特性使用 FutureExt 没有额外的堆分配:
    use futures::{Future, FutureExt}; // 0.3.5
    
    async fn a() -> usize {
        2
    }
    
    async fn b() -> usize {
        10
    }
    
    fn f() -> impl Future<Output = usize> {
        if 1 > 0 {
            a().left_future()
        } else {
            b().right_future()
        }
    }
    

    但是,这需要固定的堆栈分配。如果A占用1个字节并在99%的时间内发生,但是B占用512个字节,那么Either将始终占用512个字节(加上一些字节)。这并不总是胜利。

    装箱特征对象

    在这里,我们使用 FutureExt::boxed 返回一个特征对象:
    use futures::{Future, FutureExt}; // 0.3.5
    
    async fn a() -> usize {
        2
    }
    
    async fn b() -> usize {
        10
    }
    
    fn f() -> impl Future<Output = usize> {
        if 1 > 0 {
            a().boxed()
        } else {
            b().boxed()
        }
    }
    

    作为Matthieu M. points out,可以将两种解决方案结合起来:



    请注意,如果您具有两个以上的条件(EitherEither<A, Either<B, C>>等),则也可以堆叠Either<Either<A, B>, Either<C, D>>:
    use futures::{Future, FutureExt}; // 0.3.5
    
    async fn a() -> i32 {
        2
    }
    
    async fn b() -> i32 {
        0
    }
    
    async fn c() -> i32 {
        -2
    }
    
    fn f(v: i32) -> impl Future<Output = i32> {
        use std::cmp::Ordering;
    
        match v.cmp(&0) {
            Ordering::Less => a().left_future(),
            Ordering::Equal => b().left_future().right_future(),
            Ordering::Greater => c().right_future().right_future(),
        }
    }
    

    也可以看看:
  • Conditionally iterate over one of several possible iterators
  • 关于asynchronous - 我如何有条件地退回不同类型的 future ?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51885745/

    10-11 23:05