Hyper 0.14 Service实现中使用自有方法的生命周期错误问题
Hyper 0.14 Service结构体异步方法生命周期错误解决
问题背景
我希望在Hyper 0.14的Service结构体实现中使用自有结构体的方法,通过结构体简化请求数据访问,而非将数据传递给函数。Hyper文档说明:“Trait hyper::service::Service是从Request到Response的异步函数,是Tower的核心抽象之一,便于模块化编写网络应用。”但调用结构体异步方法时出现如下错误:
error: lifetime may not live long enough --> examples/service_struct_impl.rs:36:9 | 35 | fn call(&mut self, req: Request<Body>) -> Self::Future { | - let's call the lifetime of this reference `'1` 36 | Box::pin(self.start_process(req)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'static`
原代码:
use hyper::service::Service; use hyper::{Body, Request, Response, Server}; use hyper::StatusCode; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; type Counter = i32; type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let addr = ([127, 0, 0, 1], 3000).into(); let server = Server::bind(&addr).serve(MakeSvc { counter: 81818 }); println!("Listening on http://{}", addr); server.await?; Ok(()) } struct Svc { counter: Counter, } impl Service<Request<Body>> for Svc { type Response = Response<Body>; type Error = GenericError; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } fn call(&mut self, req: Request<Body>) -> Self::Future { Box::pin(self.start_process(req)) } } impl Svc { async fn start_process( &mut self, req: Request<Body> ) -> Result<Response<Body>, GenericError> { Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) .body(Body::from(format!("Counter is: {}", self.counter)))?) } }
错误原因
报错核心是:call方法返回的Future捕获了&mut self的引用,但你定义的Self::Future类型默认要求Future具备'static生命周期(可存活至程序结束),而&mut self的生命周期仅局限于call方法调用期间,无法满足'static要求,导致编译器抛出生命周期不匹配错误。
解决方案
方案一:使用共享状态(推荐)
通过Arc<Mutex<>>包装结构体中的共享状态,让异步方法通过克隆Arc获取状态访问权,避免Future持有&mut self的引用。这种方式适用于需要复用Service实例、处理多个请求的场景。
修改后的完整代码:
use hyper::service::{Service, MakeService}; use hyper::{Body, Request, Response, Server}; use hyper::StatusCode; use std::future::Future; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::task::{Context, Poll}; type Counter = i32; type GenericError = Box<dyn std::error::Error + Send + Sync + 'static>; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let addr = ([127, 0, 0, 1], 3000).into(); // 用Arc<Mutex>包装共享计数器 let counter = Arc::new(Mutex::new(81818)); let server = Server::bind(&addr).serve(MakeSvc { counter }); println!("Listening on http://{}", addr); server.await?; Ok(()) } // MakeSvc负责为每个连接/请求创建Service实例 struct MakeSvc { counter: Arc<Mutex<Counter>>, } impl MakeService<hyper::server::conn::AddrStream> for MakeSvc { type Response = Response<Body>; type Error = GenericError; type Service = Svc; type MakeError = GenericError; type Future = Pin<Box<dyn Future<Output = Result<Self::Service, Self::MakeError>> + Send>>; fn make_service(&mut self, _conn: &hyper::server::conn::AddrStream) -> Self::Future { // 克隆Arc,传递给新的Svc实例 let counter = self.counter.clone(); Box::pin(async move { Ok(Svc { counter }) }) } } struct Svc { counter: Arc<Mutex<Counter>>, } impl Service<Request<Body>> for Svc { type Response = Response<Body>; type Error = GenericError; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } fn call(&mut self, req: Request<Body>) -> Self::Future { // 克隆Arc,让Future持有所有权 let counter = self.counter.clone(); Box::pin(async move { // 锁定Mutex访问并修改计数器 let mut count = counter.lock().map_err(|e| format!("Mutex lock failed: {}", e))?; *count += 1; Ok(Response::builder() .status(StatusCode::OK) .body(Body::from(format!("Counter is: {}", *count)))?) }) } }
方案二:消耗Service实例(仅适用于一次性场景)
如果你的Service实例不需要复用,仅处理单个请求,可以修改call方法的签名,让它消耗self的所有权,这样Future可以持有整个结构体,无需引用:
// 修改Svc的Service实现中的call方法 impl Service<Request<Body>> for Svc { type Response = Response<Body>; type Error = GenericError; type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>; fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> { Poll::Ready(Ok(())) } // 将&mut self改为self,消耗实例所有权 fn call(self, req: Request<Body>) -> Self::Future { Box::pin(async move { Ok(Response::builder() .status(StatusCode::OK) .body(Body::from(format!("Counter is: {}", self.counter)))?) }) } }
注意:这种方式下每个Svc实例只能处理一个请求,不适用于需要持续处理请求的服务场景。
内容的提问来源于stack exchange,提问作者Developer
相关产品推荐
相关产品推荐

