我害怕终身问题。我搜索并获得了如此多的相关结果。我觉得它们之间有如此不同,我认为很难从中获得灵魂。所以我决定问。
在Hyper服务的调用中调用dao
方法时发生错误,我无法修复它!
extern crate futures;
extern crate hyper;
use futures::future::Future;
use futures::Stream;
use hyper::server::{Http, Request, Response, Service};
use hyper::StatusCode;
use std::net::SocketAddr;
trait Dao {
fn input_data(&self, data: &str) -> bool;
}
struct MysqlDao;
impl Dao for MysqlDao {
fn input_data(&self, data: &str) -> bool {
unimplemented!()
}
}
struct HelloWorld<'a> {
dao: &'a Dao,
}
impl<'a> Service for HelloWorld<'a> {
type Request = Request;
type Response = Response;
type Error = hyper::Error;
type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;
fn call(&self, req: Request) -> Self::Future {
Box::new(req.body().concat2().map(|b| {
let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
let rtn = true; // line 35 this is ok
match rtn {
true => {
return Response::new()
.with_status(StatusCode::Ok)
.with_body(String::from("ok"));
}
false => {
return Response::new()
.with_status(StatusCode::UnprocessableEntity)
.with_body(String::from("error"));
}
}
}))
}
}
fn main() {
let addr = "127.0.0.1:3000".parse().unwrap();
static DAO: MysqlDao = MysqlDao;
web_startup(&addr, &DAO);
}
fn web_startup<T: Dao>(addr: &SocketAddr, dao: &'static T) {
let server = Http::new()
.bind(addr, move || Ok(HelloWorld { dao }))
.unwrap();
server.run().unwrap();
}
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:33:9
|
33 | / Box::new(req.body().concat2().map(|b| {
34 | | let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
35 | | let rtn = true; // line 35 this is ok
36 | | match rtn {
... |
47 | | }
48 | | }))
| |___________^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the impl at 26:1...
--> src/main.rs:26:1
|
26 | / impl<'a> Service for HelloWorld<'a> {
27 | | type Request = Request;
28 | | type Response = Response;
29 | | type Error = hyper::Error;
... |
49 | | }
50 | | }
| |_^
note: ...so that the type `futures::Map<futures::stream::Concat2<hyper::Body>, [closure@src/main.rs:33:43: 48:10 self:&&HelloWorld<'a>]>` will meet its required lifetime bounds
--> src/main.rs:33:9
|
33 | / Box::new(req.body().concat2().map(|b| {
34 | | let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
35 | | let rtn = true; // line 35 this is ok
36 | | match rtn {
... |
47 | | }
48 | | }))
| |___________^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response> + 'static>, found std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response>>)
--> src/main.rs:33:9
|
33 | / Box::new(req.body().concat2().map(|b| {
34 | | let rtn = self.dao.input_data(std::str::from_utf8(b.as_ref()).unwrap());
35 | | let rtn = true; // line 35 this is ok
36 | | match rtn {
... |
47 | | }
48 | | }))
| |___________^
问题行是34.当我用第35行替换第34行时,它可以工作。
答案 0 :(得分:1)
在这段代码中,生命周期中发生了一些事情,错误信息并不是很好。
首先,您的call
函数返回特征对象;也就是说,Box<T>
其中T
是 trait 而不是具体类型。特征对象的默认生命周期为'static
,因此Box<Future>
等同于Box<Future + 'static>
。这解释了这一消息的来源:
note: ...so that expression is assignable (expected std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response> + 'static>, found std::boxed::Box<futures::Future<Error=hyper::Error, Item=hyper::Response>>)
在这种情况下,您不需要返回的Future
生效'static
。相反,您希望它与self.dao
具有相同的生命周期,因此请更改您的类型别名,如下所示:
type Future = Box<'a + Future<Item = Self::Response, Error = Self::Error>>;
第二件事是你的闭包捕获的变量。你的闭包是指self
,所以它需要保存那个引用。这意味着关闭不能超过方法的结束 - 但是您已经指定它只会活'a
;也就是说,它至少与self.dao
一样长。
请注意,此方法中的self
不的生命周期为'a
。 HelloWorld
的实例可能比其引用的dao
的生命周期更短。
要解决此问题的一半,您需要允许闭包只捕获 self.dao
而不捕获self
。所以你必须添加
let dao = self.dao;
在关闭之前,然后在闭包内引用dao
而不是self.dao
,以便它不会捕获self
。您还需要使闭包成为move
闭包,否则它最终会捕获对引用的引用,这仍将生命周期与函数的范围联系起来。
最初在评论中发布此建议的用户red75prime提出a playground with these changes。第30,33和34行是重要的。
答案 1 :(得分:0)