如何用`&self`返回将来的组合器

Seu*_*ege 4 future lifetime rust

我有这段代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

extern crate futures;

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

游乐场链接

给出生命周期错误:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

She*_*ter 5

如何返回未来的组合器 &self

您返回这样的未来self

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

struct Example {
    age: i32,
}

impl Example {
    fn make_a_future(&self) -> FutureResult<&Example, ()> {
        future::ok(self)
    }
}
Run Code Online (Sandbox Code Playgroud)

正如Tokio关于期货返还的文档中所讨论的,对于复杂的期货返还最简单的稳定解决方案是隐含性状。请注意,我们为分配了明确的生存期,self并将其用于返回值(通过+ '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)
    }
}
Run Code Online (Sandbox Code Playgroud)

真正的问题是“我怎么能对编译器撒谎,并试图将内存不安全性引入程序中?”

Box<SomeTrait + 'static>(或Box<SomeTrait>本身)意味着trait对象不能包含任何对整个程序都不持久的引用。根据定义,您的Example结构的寿命比这短。

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

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

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.

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.


归档时间:

查看次数:

903 次

最近记录:

6 年,7 月 前