Rust 是否将枚举变量包装到将来?

Rust 是否将枚举变量包装到将来?,rust,rust-tokio,Rust,Rust Tokio,我试图编译如下代码。似乎我需要帮助它理解,我希望所有匹配臂都被视为futures::future::IntoFuture,因为这是外部对回调/闭包/委托的期望 目前,所有的ARM都使用最简单的枚举变量,NothingUseful(),但我的目标最终是根据返回的HTTP状态代码和/或正文内容(如果适用)采取各种操作 extern crate futures; extern crate hyper; extern crate tokio_core; use futures::{future, Fu

我试图编译如下代码。似乎我需要帮助它理解,我希望所有匹配臂都被视为
futures::future::IntoFuture
,因为这是外部对回调/闭包/委托的期望

目前,所有的ARM都使用最简单的枚举变量,
NothingUseful()
,但我的目标最终是根据返回的HTTP状态代码和/或正文内容(如果适用)采取各种操作

extern crate futures;
extern crate hyper;
extern crate tokio_core;

use futures::{future, Future, Stream};
use hyper::{Client, Error as HyperError, Response, StatusCode, Uri};
use tokio_core::reactor::Core;

struct RecurseUrl {
    uri: Uri,
    remaining_attempts: u8,
}

enum FetchResult {
    SimpleData(u16),
    RecurseUrls(Vec<RecurseUrl>),
    NothingUseful(),
}

fn handle_redirect(res: &Response) -> future::FutureResult<FetchResult, HyperError> {
    future::ok(FetchResult::NothingUseful())
}

fn main() {
    let url = "http://someurl.com"
        .parse()
        .expect("Unable to parse URL");

    let mut core = Core::new().expect("Unable to instantiate Tokio Core");
    let client = Client::new(&core.handle());

    let work = client.get(url).and_then(|res| {

        match res.status() {
            StatusCode::TemporaryRedirect => handle_redirect(&res),
            StatusCode::PermanentRedirect => handle_redirect(&res),
            StatusCode::Ok => {
                res.body().concat2().and_then(move |body| {
                    Ok(FetchResult::NothingUseful())
                })
            },
            _ => {
                Ok(FetchResult::NothingUseful())
            }
        }
    });

    core.run(work).expect("Problem running work");
}
extern板条箱期货;
外部板条箱;
外部板条箱东京大学核心;
使用未来:{future,future,Stream};
使用hyper::{Client,Error as HyperError,Response,StatusCode,Uri};
使用tokio_堆芯::反应堆::堆芯;
结构递归{
uri:uri,
剩余的_尝试:u8,
}
枚举获取结果{
SimpleData(u16),
递归(Vec),
无意义(),
}
fn handle_重定向(res:&Response)->future::futuresult{
future::ok(FetchResult::NothingUseful())
}
fn main(){
让url=”http://someurl.com"
.parse()
.expect(“无法解析URL”);
让mut core=core::new().expect(“无法实例化Tokio core”);
让client=client::new(&core.handle());
让work=client.get(url)。然后(| res |{
匹配资源状态(){
StatusCode::TemporaryRedirect=>handle_redirect(&res),
StatusCode::PermanentRedirect=>handle_重定向(&res),
状态代码::Ok=>{
res.body().concat2().和| u然后(移动| body |{
确定(FetchResult::NothingUseful())
})
},
_ => {
确定(FetchResult::NothingUseful())
}
}
});
core.run(work.expect(“问题运行工作”);
}
错误[E0308]:匹配臂的类型不兼容
-->main.rs:34:13
|
34 |/match res.status(){
35 | |状态代码::临时重定向=>句柄重定向(&res),
36 | | StatusCode::PermanentRedirect=>handle_重定向(&res),
37 | |状态代码::Ok=>{
...  |
44 | |                 }
45 | |             }
||uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu`
|
=注:预期类型“futures::FutureResult”`
找到类型`futures::然后`
注意:将arm与不兼容的类型匹配
-->main.rs:37:35
|
37 |状态代码::Ok=>{
|  ___________________________________^
38 | | res.body().concat2().然后|移动| body |{
39 | |好(FetchResult::NothingUseful())
40 | |                     })
41 | |                 },
| |_________________^
我希望所有匹配臂都被视为
futures::future::IntoFuture
,因为这是外部
和\u then
对回调/关闭/委托的期望

和_然后
期望闭包的返回类型是一个单一的具体类型,它实现了特征
到未来
。您的
match
返回多个具体类型-这在Rust中是不允许的,因为编译器不知道要分配多少堆栈空间

您需要将所有各种类型转换为单个统一类型。最简单的方法是将它们全部装箱,创建一个trait对象(
box
):

然后,您可以通过以下方式处理从响应体中读取URI的操作:

use futures::stream::{Stream, FuturesUnordered, Concat2};

struct WebCrawler {
    client: Client<HttpConnector>,
    to_fetch: FuturesUnordered<FutureResponse>,
    fetching: FuturesUnordered<Concat2<hyper::Body>>,
}

impl WebCrawler {
    fn new(client: Client<HttpConnector>, uri: Uri) -> Self {
        let future = client.get(uri);
        let to_fetch: FuturesUnordered<_> = Some(future).into_iter().collect();

        Self {
            client,
            to_fetch,
            fetching: FuturesUnordered::new(),
        }
    }
}

impl Stream for WebCrawler {
    type Item = hyper::Chunk;
    type Error = hyper::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            match self.to_fetch.poll()? {
                Async::Ready(Some(s)) => {
                    self.fetching.push(s.body().concat2())
                },
                Async::Ready(None) | Async::NotReady => break,
            }
        }

        loop {
            match self.fetching.poll()? {
                Async::Ready(Some(body)) => {
                    for uri in get_uris_from_body(&body) {
                        self.to_fetch.push(self.client.get(uri));
                    }
                    return Ok(Async::Ready(Some(body)));
                },
                Async::Ready(None) | Async::NotReady => break,
            }
        }

        if self.to_fetch.is_empty() && self.fetching.is_empty() {
            Ok(Async::Ready(None))
        } else {
            Ok(Async::NotReady)
        }
    }
}

fn get_uris_from_body(_body: &hyper::Chunk) -> Vec<Uri> {
    unimplemented!()
}
use futures::stream:{stream,FuturesUnordered,Concat2};
结构WebCrawler{
客户:客户,,
获取:未来已订购,
取景:未来,
}
IMPLWebCrawler{
fn新(客户端:客户端,uri:uri)->Self{
让future=client.get(uri);
let to_fetch:FuturesUnordered=Some(future).into_iter().collect();
自我{
客户
去拿,
获取:FuturesUnordered::new(),
}
}
}
WebCrawler的impl流{
类型Item=hyper::Chunk;
类型错误=hyper::Error;
fn轮询(&mut self)->轮询{
环路{
是否将self.to_fetch.poll()匹配{
Async::Ready(一些))=>{
self.fetching.push(s.body().concat2())
},
Async::Ready(无)| Async::NotReady=>break,
}
}
环路{
匹配self.fetching.poll(){
Async::Ready(Some(body))=>{
对于从正文获取uri中的uri(&body){
self.to_fetch.push(self.client.get(uri));
}
返回Ok(Async::Ready(Some(body));
},
Async::Ready(无)| Async::NotReady=>break,
}
}
如果self.to_fetch.is_empty()&&self.fetching.is_empty(){
正常(异步::就绪(无))
}否则{
Ok(异步::NotReady)
}
}
}
fn从\u body(\u body:&hyper::Chunk)->Vec获取\u uris\u{
未执行!()
}

这一实现是仿效的。你需要对它进行增强,以通过深入的爬行并管理它,但我认为这是一个很好的草图,说明了什么是可能的。

你是否理解
到未来
是一种特性,并且没有办法“仅仅”将某个东西变成稳定生锈的特性?@Shepmaster我理解这是一种特性。我希望我可以添加一些明确的类型提示或铸造或其他东西。使用future::ok()让每个arm返回一个实际的未来是很容易的,但是我遇到了一些问题,其中一些结果impl是,然后是,还有一些是futuresult,当我尝试将它们分配给一个变量类型,该变量类型具有它们都应该具有的共同特征时,它会抱怨没有标记大小。也许我应该采取一些完全不同的方法?你能澄清一下为每个变体创建一个枚举,并通过授权给每个内部实现来实现未来吗
#[macro_use]
extern crate futures;
extern crate hyper;
extern crate tokio_core;

use futures::{Async, Future, Poll};
use hyper::client::{FutureResponse, HttpConnector};
use hyper::{Client, Response, StatusCode, Uri};
use tokio_core::reactor::Core;

struct RecurseUrl {
    client: Client<HttpConnector>,
    future: FutureResponse,
    remaining_attempts: u8,
}

impl RecurseUrl {
    fn new(client: Client<HttpConnector>, uri: Uri) -> Self {
        let future = client.get(uri);
        Self {
            client,
            future,
            remaining_attempts: 3,
        }
    }
}

impl Future for RecurseUrl {
    type Item = hyper::Response;
    type Error = hyper::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let response = try_ready!(self.future.poll());

        match response.status() {
            StatusCode::TemporaryRedirect | StatusCode::PermanentRedirect => {
                if self.remaining_attempts == 0 {
                    panic!("return a real error")
                }

                let next_uri = get_redirect_uri_from_response(&response);
                let next_future = self.client.get(next_uri);
                self.future = next_future;
                self.remaining_attempts -= 1;

                Ok(Async::NotReady)
            }
            StatusCode::Ok => Ok(Async::Ready(response)),
            _ => panic!("return a real error"),
        }
    }
}

fn get_redirect_uri_from_response(_response: &Response) -> Uri {
    unimplemented!()
}

fn main() {
    let uri = "http://someurl.com".parse().expect("Unable to parse URL");

    let mut core = Core::new().expect("Unable to instantiate Tokio Core");
    let client = Client::new(&core.handle());

    let work = RecurseUrl::new(client, uri);
    core.run(work).expect("Problem running work");
}
use futures::stream::{Stream, FuturesUnordered, Concat2};

struct WebCrawler {
    client: Client<HttpConnector>,
    to_fetch: FuturesUnordered<FutureResponse>,
    fetching: FuturesUnordered<Concat2<hyper::Body>>,
}

impl WebCrawler {
    fn new(client: Client<HttpConnector>, uri: Uri) -> Self {
        let future = client.get(uri);
        let to_fetch: FuturesUnordered<_> = Some(future).into_iter().collect();

        Self {
            client,
            to_fetch,
            fetching: FuturesUnordered::new(),
        }
    }
}

impl Stream for WebCrawler {
    type Item = hyper::Chunk;
    type Error = hyper::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        loop {
            match self.to_fetch.poll()? {
                Async::Ready(Some(s)) => {
                    self.fetching.push(s.body().concat2())
                },
                Async::Ready(None) | Async::NotReady => break,
            }
        }

        loop {
            match self.fetching.poll()? {
                Async::Ready(Some(body)) => {
                    for uri in get_uris_from_body(&body) {
                        self.to_fetch.push(self.client.get(uri));
                    }
                    return Ok(Async::Ready(Some(body)));
                },
                Async::Ready(None) | Async::NotReady => break,
            }
        }

        if self.to_fetch.is_empty() && self.fetching.is_empty() {
            Ok(Async::Ready(None))
        } else {
            Ok(Async::NotReady)
        }
    }
}

fn get_uris_from_body(_body: &hyper::Chunk) -> Vec<Uri> {
    unimplemented!()
}