gpt4 book ai didi

rust - 如何与 super 请求处理程序共享不可变的配置数据?

转载 作者:行者123 更新时间:2023-11-29 08:12:02 27 4
gpt4 key购买 nike

我正在尝试用 Rust 开发一个基于 super 的服务器应用程序。有一个 INI 文件保存诸如绑定(bind) IP、数据库等配置。

我不想在每个请求上解析 INI 文件,并且可以保留配置数据直到服务器重新启动。如何向请求处理程序提供已解析数据的结构?

我尝试了几种方法,例如使用 std::sync::Arc,但到目前为止唯一有效的是使用 static,但我想避免不安全 block 。

这是一个完整的(非工作)示例:

Cargo.toml

[package]
name = "demo"
version = "0.1.0"
edition = "2018"

[dependencies]
hyper = "0.12"
rust-ini = "0.13"

demo.ini

[Demo]
value="some value"

src/main.rs

extern crate hyper;
extern crate ini;

use hyper::rt::{self, Future};
use hyper::service::service_fn_ok;
use hyper::{Body, Request, Response, Server};
use ini::Ini;
use std::sync::Arc;

pub struct Config {
pub value: String,
}

fn request_handler(req: Request<Body>, config: &Config) -> Response<Body> {
let user_agent = req.headers()["user-agent"].to_str().unwrap();
println!("user agent: {:?}", &user_agent);
println!("config value: {:?}", &config.value);
Response::new(Body::from(""))
}

fn read_ini(config_file: &str) -> Arc<Config> {
match Ini::load_from_file(config_file) {
Ok(c) => {
let demo_section = c.section(Some("Demo".to_owned())).unwrap();
let value = match demo_section.get("value") {
Some(v) => v,
None => {
println!("Error reading ini");
std::process::exit(-1)
}
};

Arc::<Config>::new(Config {
value: value.to_string(),
})
}
_ => {
eprintln!("CRITICAL: Could not open config file: {:?}", &config_file);
std::process::exit(-1)
}
}
}

fn main() {
let cfg = read_ini("demo.ini");
let addr = "127.0.0.1:3000".parse().unwrap();

let server = Server::bind(&addr)
.serve(|| service_fn_ok(move |req: Request<Body>| request_handler(req, &cfg.clone())))
.map_err(|e| println!("server error: {}", e));

rt::run(server);
}

错误

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
--> src/main.rs:49:16
|
49 | .serve(|| service_fn_ok(move |req: Request<Body>| request_handler(req, &cfg.clone())))
| ^^^^^^^^^^^^^^^^^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | closure is `FnOnce` because it moves the variable `cfg` out of its environment
| this closure implements `FnOnce`, not `Fn`

最佳答案

要仔细观察 serve 中的两个闭包级别。使用 move 定义的第二级闭包(传递给 service_fn_ok)将尝试将唯一的实例 cfg 移入其中,甚至在对 clone() 进行任何调用之前。如果不进行克隆,则无法多次执行此移动,因此闭包将仅实现 FnOnce。这是双重移动的情况:第二个闭包想要在只允许它执行一次的环境中接收资源。

为了解决这个问题,我们希望第一个闭包接收cfg,并每次都克隆它。

fn main() {
let cfg = read_ini("demo.ini");
let addr = "127.0.0.1:3000".parse().unwrap();

let server = Server::bind(&addr)
.serve(move || {
let cfg = cfg.clone();
service_fn_ok(move |req| request_handler(req, &cfg))
})
.map_err(|e| println!("server error: {}", e));

rt::run(server);
}

关于rust - 如何与 super 请求处理程序共享不可变的配置数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55606450/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com