如何使用`& self`返回未来的组合子

时间:2018-02-04 21:50:48

标签: rust future lifetime

我有这段代码:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    //
    ui->setupUi(this);
    centralWidget = new QWidget();
    centralWidget->setGeometry(width,height);
    chatWidget=new ChatWidget(centralWidget); // the subclassed QWidget
    setCentralWidget(centralWidget);

    // added testing
    QPushButton *btn = new QPushButton("MyButton",centralWidget);
    btn->setGeometry(100,100,100,100);
    btn->setMaximumSize(100,100);
    connect(btn,&QPushButton::clicked, chatWidget, &ChatWidget::displayChatAfterButtonPressed);
 }

请注意ChatWidget::ChatWidget(QWidget *parent):QWidget(parent) { QLabel *lbl; lbl=new QLabel(this); lbl->setText("Hello World 1"); } void ChatWidget::displayChatAfterButtonPressed() { QLabel *lbl; lbl=new QLabel(this); lbl->setText("Hello World 2"); lbl->show(); } 上的生命周期参数 - 它用于避免生命周期问题。

这不会编译,因为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因此导致生命周期问题。 Box<Future<Item = Response, Error = Error>>需要'static

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

hyper::Server::Service

playground link

给出了生命周期错误:

'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) } } 构建并使用Rust v1.25.0(每晚)

1 个答案:

答案 0 :(得分:4)

  

如何使用&self

返回未来的组合子

你返回一个引用self的未来:

extern crate futures;

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

struct Example {
    age: i32,
}

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

正如Tokio documentation on returning futures中所讨论的,返回复杂未来的最简单稳定的解决方案是盒装特征对象。请注意,我们将显式生存期分配给self并在返回的特征对象中使用它(通过+ 'a):

use futures::Future;

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

你的真正的问题是&#34;我怎么能欺骗编译器并试图在我的程序中引入内存不安全?&#34;

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

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

对于具有类似限制的线程,有很多问题要求相同的问题。小样本:

就像在这些情况下一样,您试图在变量被破坏之后 之后共享对变量的引用。诸如C或C ++之类的语言允许你这样做,只是让你的程序在被释放后访问该变量时将来会在一个看似随机的时间点崩溃。顺便说一句,崩溃是的情况;信息泄漏或代码执行也是可能的。

与线程的情况一样,您必须确保这不会发生。最简单的方法是将变量移到未来,而不是共享它。另一种选择是在变量周围使用Arc之类的东西,克隆Arc并将克隆交给未来。