将未来的结果转换为另一个未来

Converting a future result in another future

我有一个 return 具有 User 特征的未来函数。我有两个具体的实现:AnonymousUserBaseUser。要获得 BaseUser,在身份验证后,我必须去数据库获取它,这可能会成功也可能不会成功,并且 return 具有正确类型的新未来。我尝试了以下 (playground):

extern crate futures; // 0.1.23
extern crate rand; // 0.5.4

use futures::future::{ok, Future};
use std::io::Error;

trait User {}

#[derive(Debug)]
struct AnonymousUser;
impl User for AnonymousUser {}

#[derive(Debug)]
struct BaseUser;
impl User for BaseUser {}

fn fetch_base_user() -> impl Future<Item = BaseUser, Error = Error> {
    ok(BaseUser)
}

fn run_future() -> impl Future<Item = impl User, Error = Error> {
    match rand::random::<bool>() {
        true => fetch_base_user().from_err().then(move |res| match res {
            Ok(user) => ok(user),
            Err(_) => ok(AnonymousUser),
        }),
        false => ok(AnonymousUser),
    }
}

fn main() {
    run_future().and_then(move |user| println!("User {:?}", user));
}

这失败了,因为 then 函数的 return 需要一个 BaseUser:

error[E0308]: match arms have incompatible types
  --> src/main.rs:23:62
   |
23 |           true => fetch_base_user().from_err().then(move |res| match res {
   |  ______________________________________________________________^
24 | |             Ok(user) => ok(user),
25 | |             Err(_) => ok(AnonymousUser),
   | |                       ----------------- match arm with an incompatible type
26 | |         }),
   | |_________^ expected struct `BaseUser`, found struct `AnonymousUser`
   |
   = note: expected type `futures::FutureResult<BaseUser, _>`
              found type `futures::FutureResult<AnonymousUser, _>`

我尝试强制 return 类型:

use futures::future::FutureResult;

fn run_future() -> impl Future<Item=impl User, Error=Error> {
    match rand::random::<bool>() {
        true => fetch_base_user().from_err().then(move |res| ->
        FutureResult<impl User, Error> { // Forcing the result type here
            match res {
                Ok(user) => ok(user),
                Err(_) => ok(AnonymousUser),
            }
        }),
        false => ok(AnonymousUser),
    }
}

失败:

error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
  --> src/main.rs:27:22
   |
27 |         FutureResult<impl User, Error> { // Forcing the result type here
   |                      ^^^^^^^^^

我尝试使用 Boxes 对 return 进行返工,这几乎成功了 (playground)

fn run_future() -> impl Future<Item = Box<impl User>, Error = Error> {
    match rand::random::<bool>() {
        true => fetch_base_user()
            .from_err()
            .then(move |res| -> FutureResult<Box<User>, Error> {
                match res {
                    Ok(user) => ok(Box::new(user) as Box<User>),
                    Err(_) => ok(Box::new(AnonymousUser) as Box<User>),
                }
            }),
        false => ok(Box::new(AnonymousUser) as Box<User>),
    }
}

失败

error[E0308]: match arms have incompatible types
  --> src/main.rs:22:5
   |
22 | /     match rand::random::<bool>() {
23 | |         true => fetch_base_user().from_err().then(move |res| match res {
24 | |             Ok(user) => ok(Box::new(user) as Box<User>),
25 | |             Err(_) => ok(Box::new(AnonymousUser) as Box<User>),
26 | |         }),
27 | |         false => ok(Box::new(AnonymousUser) as Box<User>),
   | |                  ---------------------------------------- match arm with an incompatible type
28 | |     }
   | |_____^ expected struct `futures::Then`, found struct `futures::FutureResult`
   |
   = note: expected type `futures::Then<futures::future::FromErr<impl futures::Future, _>, futures::FutureResult<std::boxed::Box<User>, _>, [closure@src/main.rs:23:51: 26:10]>`
              found type `futures::FutureResult<std::boxed::Box<User>, _>`

所以我想这只是强制两者成为相同结果类型的问题

最后 shepmaster 的评论让我通过另一个问题得到了回应:

基本上使用 Either::A 和 Either::B 就可以解决问题。如果不对参数进行装箱,我仍然无法使其工作,但这可能是一个不同的问题。