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

时间:2018-08-17 01:26:56

标签: rust rust-tokio

我有一个函数可以返回具有User特征的将来。我有两个具体的实现:AnonymousUserBaseUser。要获得BaseUser,在身份验证之后,我必须转到数据库并获取该数据库(可能成功也可能不会成功),然后以正确的类型返回新的Future。我已经尝试了以下(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函数需要一个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, _>`

我尝试强制返回类型:

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

我尝试使用Box es返工,几乎可以工作(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>, _>`

所以我想这只是强制将两者设为相同的结果类型

1 个答案:

答案 0 :(得分:0)

最后,来自shepmaster的评论引导我通过另一个问题进行了回复:How do I conditionally return different types of futures?

基本上使用Either :: A和Either :: B解决了此问题。如果没有将参数装箱,我仍然无法使其正常工作,但这可能是一个不同的问题。