述語に応じて、ある未来または別の未来を返すメソッドがあります。言い換えると、futureを返す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))
}
}
これはコンパイルされません:
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]>`
先物は異なる方法で作成され、クロージャを保持する可能性があるため、それらのタイプは等しくありません。理想的には、ソリューションはBox
esを使用しないでしょう。これは、私の非同期ロジックの残りの部分がそれらを使用しないためです。
先物のif-elseロジックは通常どのように実行されますか?
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.が指摘 のように、2つのソリューションを組み合わせることができます。
大きな
B
:Either(A, Box<B>)
の場合の中間的な解決策があることに注意してください。このように、ヒープ割り当ての料金は、それがB
であるまれなケースでのみ支払われます。
3つ以上の条件(_Either<A, Either<B, C>>
_; _Either<Either<A, B>, Either<C, D>>
_など)がある場合は、Either
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))),
}
}
_
参照: