是否有可能 Future::and_then 有条件地 return 不同的期货?
Is it possible to have Future::and_then conditionally return different futures?
在我的代码的这个简化版本中,我想有时执行标记的行,有时不执行,可能会返回一个错误:
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(())
}
因为期货的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
, while 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(|_| ()) })
另一个解决方案是将您的 return 值装箱:
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(()))
}
第三个解决方案是总是return一个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);
})
或者在对 futures::future::err
.
的调用中使用实现 From<hyper::Error>
的类型
在我的代码的这个简化版本中,我想有时执行标记的行,有时不执行,可能会返回一个错误:
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(())
}
因为期货的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
, while 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(|_| ()) })
另一个解决方案是将您的 return 值装箱:
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(()))
}
第三个解决方案是总是return一个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);
})
或者在对 futures::future::err
.
From<hyper::Error>
的类型