为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

红糖糍粑 2019-12-06 10:22:06
我有一种方法,根据谓词的不同,它会返回一个将来或另一个。换句话说,一个if-else表达式返回一个future:extern crate futures; // 0.1.23use 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逻辑通常如何完成?
查看完整描述

3 回答

?
白衣染霜花

TA贡献1796条经验 获得超10个赞

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

    }

}

但是,这需要固定的堆栈分配。如果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)))

    }

}

正如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 = ()> {

    use std::cmp::Ordering;

    match v.cmp(&0) {

        Ordering::Less => Either::A(future::ok(2).map(|x| -x)),

        Ordering::Equal => Either::B(Either::A(future::ok(0))),

        Ordering::Greater => Either::B(Either::B(future::ok(-2).map(|x| x * x))),

    }

}


查看完整回答
反对 回复 2019-12-06
?
开满天机

TA贡献1786条经验 获得超12个赞

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

查看完整回答
反对 回复 2019-12-06
?
MMTTMM

TA贡献1869条经验 获得超4个赞

我给出了3个(奇数)和4个(偶数)条件的示例:如果您有2个以上的条件(Either<A, Either<B, C>>Either<Either<A, B>, Either<C, D>>等)。我不明白你为什么用Empty

查看完整回答
反对 回复 2019-12-06
  • 3 回答
  • 0 关注
  • 560 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信