Ответ 1
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)))
}
}
Как отмечает Матье М., два решения можно объединить:
Я хотел бы отметить, что для случая большого
B
:Either(A, Box<B>)
существует среднее решение. Таким образом, вы платите только за выделение кучи в тех редких случаях, когда этоB
Обратите внимание, что вы также можете сложить Either
, если у вас более двух условий (Either<A, Either<B, C>>
; Either<Either<A, B>, Either<C, D>>
и т.д.):
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))),
}
}
Смотрите также: