如何返回带有& self的将来的组合器 [英] How to return a future combinator with `&self`

查看:43
本文介绍了如何返回带有& self的将来的组合器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有使用Future v0.1的这段代码:

I have this piece of code using futures v0.1:

impl ArcService for (Box<MiddleWare<Request>>, Box<ArcService>) {
    fn call(&self, req: Request, res: Response) -> Box<Future<Item = Response, Error = Error>> {
        box self.0.call(req).and_then(move |req| self.1.call(req, res))
    }
}

pub trait ArcService: Send + Sync {
    fn call(&self, req: Request, res: Response) -> Box<Future<Item = Response, Error = Error>>;
}

pub trait MiddleWare<T>: Sync + Send {
    fn call<'a>(&'a self, param: T) -> Box<Future<Item = T, Error = Error> + 'a>;
}

type MiddleWareFuture<'a, I> = Box<Future<Item = I, Error = Error> + 'a>;

impl MiddleWare<Request> for Vec<Box<MiddleWare<Request>>> {
    fn call(&self, request: Request) -> MiddleWareFuture<Request> {
        self.iter()
            .fold(box Ok(request).into_future(), |request, middleware| {
                box request.and_then(move |req| middleware.call(req))
            })
    }
}

pub struct ArcRouter {
    routes: HashMap<Method, Box<ArcService>>,
}

// Service implementation
impl hyper::Server::Service for ArcRouter {
    type Response = Response;
    type Request = Request;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, req: Request) -> Box<Future<Item = Self::Response, Error = Self::Error>> {
        if let Some(routeMatch) = self.matchRoute(req.path(), req.method()) {
            let mut request: ArcRequest = req.into();
            request.paramsMap.insert(routeMatch.params);
            let response = routeMatch.handler //handler is ArcService
                    .call(request, ArcResponse::new())
                    .map(|res| res.into());
            return box response;
        }

        // TODO: this should be handled by a user defined 404 handler
        return box Ok(Response::new().with_status(StatusCode::NotFound)).into_future();
    }
}

请注意Middleware上的生命周期参数-用于避免生命周期问题.

Note the lifetime parameter on Middleware — it is used to avoid lifetime issues.

这不会编译,因为Box<Future<Item = Response, Error = Error>>是隐式的'static,因此会导致生命周期问题. hyper::Server::Service需要'static Future

This does not compile because Box<Future<Item = Response, Error = Error>> is implicitly 'static and therefore causes lifetime issues. hyper::Server::Service requires a 'static Future

这是一个恰当地描述我的问题的示例:

Here is an example that aptly describes my problem:

extern crate futures; // v0.1 (old)

use futures::{future, Future};

struct Example {
    age: i32,
}

// trait is defined in an external crate. You can't change it's definition
trait MakeFuture {
    fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>>;
}

impl MakeFuture for Example {
    fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>> {
        let f = future::ok(self).map(|ex| ex.age + 1);
        Box::new(f)
    }
}

游乐场链接

给出寿命错误:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:16:28
   |
16 |         let f = future::ok(self).map(|ex| ex.age + 1);
   |                            ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 15:5...
  --> src/main.rs:15:5
   |
15 | /     fn make_a_future(&self) -> Box<Future<Item = i32, Error = ()>> {
16 | |         let f = future::ok(self).map(|ex| ex.age + 1);
17 | |         Box::new(f)
18 | |     }
   | |_____^
note: ...so that expression is assignable (expected &Example, found &Example)
  --> src/main.rs:16:28
   |
16 |         let f = future::ok(self).map(|ex| ex.age + 1);
   |                            ^^^^
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Item=i32, Error=()> + 'static>, found std::boxed::Box<futures::Future<Item=i32, Error=()>>)
  --> src/main.rs:17:9
   |
17 |         Box::new(f)
   |         ^^^^^^^^^^^

有没有办法解决这个问题?我正在使用hyper::Service构建并使用Rust v1.25.0(每晚)

Is there a way to get around this? I'm building with hyper::Service and using Rust v1.25.0 (nightly)

推荐答案

如何使用&self

您将返回引用self的未来,如下所示:

You return a future that refers to self like this:

use futures::future::{self, FutureResult}; // 0.1.28

struct Example {
    age: i32,
}

impl Example {
    fn make_a_future(&self) -> FutureResult<&Example, ()> {
        future::ok(self)
    }
}

Tokio有关返还期货的文档中所述,回报复杂未来的最简单的稳定解决方案是 impl Trait .请注意,我们为self分配了明确的生存期,并将其用于返回值(通过+ 'a):

As discussed in the Tokio documentation on returning futures, the easiest stable solution to returning a complicated future is a impl Trait. Note that we assign an explicit lifetime to self and use that in the returned value (via + 'a):

use futures::{future, Future}; // 0.1.28

struct Example {
    age: i32,
}

impl Example {
    fn make_a_future<'a>(&'a self) -> impl Future<Item = i32, Error = ()> + 'a {
        future::ok(self).map(|ex| ex.age + 1)
    }
}


您的真实问题是我如何对编译器撒谎,并试图将内存不安全性引入我的程序中?"


Your real question is "how can I lie to the compiler and attempt to introduce memory unsafety into my program?"

Box<SomeTrait + 'static>(或Box<SomeTrait>本身)表示特征对象不能包含不对整个程序持续的任何引用.根据定义,您的Example结构的寿命比该寿命短.

Box<SomeTrait + 'static> (or Box<SomeTrait> by itself) means that the trait object must not contain any references that do not last for the entire program. By definition, your Example struct has a shorter lifetime than that.

这与期货无关.这是一个基本的Rust概念.

This has nothing to do with futures. This is a fundamental Rust concept.

关于线程,有很多问相同问题的问题,它们具有相似的限制.少量采样:

There are many questions that ask the same thing in regards to threads, which have similar restrictions. A small sampling:

  • Lifetime of variables passed to a new thread
  • How do I use static lifetimes with threads?
  • The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
  • Lifetime troubles sharing references between threads

像在这些情况下一样,您尝试与变量被破坏后 之后可能存在的变量共享引用.诸如C或C ++之类的语言会让您执行此操作,只是使您的程序在将来释放变量后被访问时,在看似随机的时间点崩溃.顺便说一句,崩溃是 good 案例;信息泄漏或代码执行也是可能的.

Like in those cases, you are attempting to share a reference to a variable with something that may exist after the variable is destroyed. Languages such as C or C++ would let you do this, only to have your program crash at a seemingly random point in time in the future when that variable is accessed after being freed. The crash is the good case, by the way; information leaks or code execution is also possible.

就像线程一样,您必须确保不会发生这种情况.最简单的方法是将变量移至未来,而不是完全共享.另一种选择是在变量周围使用Arc之类的东西,克隆Arc并将克隆传递给将来.

Like the case for threads, you have to ensure that this doesn't happen. The easiest way is to move the variable into the future, not sharing it at all. Another option is to use something like an Arc around your variable, clone the Arc and hand the clone to the future.

这篇关于如何返回带有&amp; self的将来的组合器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆