Как я могу условно вернуть различные типы фьючерсов?
У меня есть метод, который, в зависимости от предиката, вернет то или иное будущее. Другими словами, выражение 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, так как остальная часть моей асинхронной логики не использует их.
, Какой-то логики в фьючерсы обычно делается?
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
s, Если у вас есть более 2 Условий (Either<A, Either<B, C>>
;Either<Either<A, B>, Either<C, D>>
, и т.д.):См. также: