如何为闭包中捕获的值设置生命周期?
解决闭包捕获值的生命周期问题(Rocket框架场景)
首先咱们拆解下你遇到的核心问题:你在main里创建的client是局部栈变量,它的生命周期只局限于main函数执行期间,但Rocket的AdHoc::on_request要求传入的闭包必须满足'static生命周期——因为Rocket会在整个应用运行期间持有这个fairing,闭包捕获的变量得能存活到应用结束,这就和client的生命周期产生了冲突。
要解决这个问题,核心是让client的生命周期延长到整个应用运行时,同时保证多线程环境下的安全访问(Rocket是多线程处理请求的)。这里推荐用Arc<Mutex<T>>来包装你的Client,具体步骤如下:
1. 导入必要的同步工具
先引入Rust标准库的Arc和Mutex,实现线程安全的共享所有权:
use std::sync::{Arc, Mutex};
2. 包装Client实例
把原来的client用Arc<Mutex>包裹,这样就能在多个线程间安全共享:
let client = Arc::new(Mutex::new(Client::new("127.0.0.1:9125", "miniserver-rs").unwrap()));
3. 在闭包中捕获共享的Client
先clone一份Arc(这是轻量级操作,只是增加引用计数),然后在闭包里通过lock()获取Client的可变引用(因为incr方法需要&mut self):
.attach(AdHoc::on_request(move |request, data| { let client = client.clone(); let mut client = client.lock().unwrap(); client.incr("http.requests"); println!("Request URI: {}", request.uri()); }))
完整修正后的代码
#![feature(plugin)] #![plugin(rocket_codegen)] extern crate rocket; extern crate statsd; use rocket::{Data, Request}; use rocket::fairing::AdHoc; use statsd::Client; use std::sync::{Arc, Mutex}; #[get("/")] fn index() -> &'static str { "Hello, World" } fn main() { let client = Arc::new(Mutex::new(Client::new("127.0.0.1:9125", "miniserver-rs").unwrap())); rocket::ignite() .attach(AdHoc::on_request(move |request, data| { let client = client.clone(); let mut client = client.lock().unwrap(); client.incr("http.requests"); println!("Request URI: {}", request.uri()); })) .mount("/", routes![index]) .launch(); }
额外说明
Arc允许我们在多个线程间共享同一个值的所有权,每次clone只是增加引用计数,开销极小;Mutex保证同一时间只有一个线程能访问内部的Client,避免多线程竞争导致的数据异常;- 如果你使用的是Rocket 0.5+异步版本,需要改用
tokio::sync::Mutex,因为标准库的Mutex在异步环境下会阻塞整个执行器,但从你的代码特征来看应该是0.4版本,用标准库的Mutex就没问题。
内容的提问来源于stack exchange,提问作者cdelmas
相关产品推荐
相关产品推荐

