rust - 是否可以让 Future::and_then 有条件地返回不同的 future ?

标签 rust future hyper rust-tokio

<分区>

在我的代码的这个简化版本中,我想有时执行标记的行,有时不执行,可能会返回一个错误:

extern crate futures; // 0.1.26
extern crate hyper; // 0.12.25

use hyper::rt::{Future, Stream};
use std::str::FromStr;

struct MyStream {}

impl Stream for MyStream {
    type Item = hyper::Uri;
    type Error = ();

    fn poll(&mut self) -> Result<futures::Async<Option<Self::Item>>, Self::Error> {
        Ok(futures::Async::Ready(Some(
            hyper::Uri::from_str("http://www.google.com/").unwrap(),
        )))
    }
}

fn main() {
    let client = hyper::Client::new();
    let futs = MyStream {}
        .map(move |uri| {
            client
                .get(uri)
                .and_then(|res| {
                    res.into_body().concat2() // <----------------
                })
                .map(|body| {
                    println!("len is {}.", body.len());
                })
                .map_err(|e| {
                    println!("Error: {:?}", e);
                })
        })
        .buffer_unordered(2)
        .for_each(|_| Ok(()));

    hyper::rt::run(futs);
}

我想我可以用这样的东西替换这一行:

let do_i_want_to_get_the_full_page = true;
if do_i_want_to_get_the_full_page {
    res.into_body().concat2().map_err(|_| ())
} else {
    futures::future::err(())
}

因为 futures 的 Error 部分是相同的,所以 Item 部分可以推断出来。但是,它不起作用。我该怎么做?

这是我得到的错误:

error[E0308]: if and else have incompatible types
  --> src/main.rs:31:25
   |
28 | /                     if do_i_want_to_get_the_full_page {
29 | |                         res.into_body().concat2().map_err(|_| ())
   | |                         ----------------------------------------- expected because of this
30 | |                     } else {
31 | |                         futures::future::err(())
   | |                         ^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `futures::MapErr`, found struct `futures::FutureResult`
32 | |                     }
   | |_____________________- if and else have incompatible types
   |
   = note: expected type `futures::MapErr<futures::stream::Concat2<hyper::Body>, [closure@src/main.rs:29:59: 29:65]>`
              found type `futures::FutureResult<_, ()>`

最佳答案

问题是 map_err returns a struct MapErr , 而 err returns a struct FutureResult .

解决问题的一种方法是像这样统一它们:

let f = if do_i_want_to_get_the_full_page {
    futures::future::ok(())
} else {
    futures::future::err(())
};
f.and_then (|_| { res.into_body().concat2().map_err(|_| ()) })

另一个解决方案是装箱您的返回值:

if do_i_want_to_get_the_full_page {
    Box::<Future<_, _>>::new (res.into_body().concat2().map_err(|_| ()))
} else {
    Box::<Future<_, _>>::new (futures::future::err(()))
}

第三种解决方案是始终返回 MapErr :

if do_i_want_to_get_the_full_page {
    res.into_body().concat2().map_err(|_| ())
} else {
    futures::future::err(()).map_err(|_| ())
}

但是,您会遇到一个问题,因为 client.get(…).and_then(…) 的错误类型必须实现 From<hyper::Error> :

error[E0271]: type mismatch resolving `<futures::AndThen<futures::FutureResult<(), ()>, futures::MapErr<futures::stream::Concat2<hyper::Body>, [closure@src/main.rs:34:70: 34:76]>, [closure@src/main.rs:34:32: 34:77 res:_]> as futures::IntoFuture>::Error == hyper::Error`
  --> src/main.rs:28:18
   |
28 |                 .and_then(|res| {
   |                  ^^^^^^^^ expected (), found struct `hyper::Error`
   |
   = note: expected type `()`
              found type `hyper::Error`

如果你不关心这个错误,你可以在 and_then 之前把它映射掉:

client
    .get(uri)
    .map_err (|_| ())
    .and_then(|res| {
        let f = if do_i_want_to_get_the_full_page {
            futures::future::ok(())
        } else {
            futures::future::err(())
        };
        f.and_then(|_| res.into_body().concat2().map_err(|_| ()))
    }).map(|body| {
        println!("len is {}.", body.len());
    }).map_err(|e| {
        println!("Error: {:?}", e);
    })

playground

或使用实现 From<hyper::Error> 的类型在您调用 futures::future::err 的电话中.

关于rust - 是否可以让 Future::and_then 有条件地返回不同的 future ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52143836/

相关文章:

rust - 将可变 Arc 引用传递给 hyper service_fn 处理程序

rust - Rust 如何在没有重载函数的情况下设法拥有泛型?

reference - 如何为对结构的引用实现 Add 特性?

scala - Scala 上的类型不匹配用于理解 : scala. concurrent.Future

c++ - 如果在promise.set_value()之后调用future.get()会发生什么?

rust - 如何阅读基于 Tokio 的 Hyper 请求的整个主体?

server - 如何在 hyper 中提供静态文件/目录?

java - 如何自动化 Rust 代码的 Java 绑定(bind)?

vector - 如何从 Rust 中的向量中获取引用的一部分?

scala - Scala future 的 "Speculative execution"