我只是从锈病开始,因为我是一个通过学习来学习的人,我想要完全理解在铁锈里解决这种案件的惯用方法。
我在聊天中得到的许多回复都是一样的:“克隆人!”
我不想clone(),我在这里学习更好的方法,否则我将回到使用Golang或Javascript。
另外,我害怕克隆,因为在这种情况下,我不想分配相同的数据(Config)多次。
即使我与许多工作人员一起工作(actix就是这种情况),我也希望使用对该结构的引用,而不是每次分配相同数据的时候都克隆。我说错了吗?
在下面的简单代码中,如您所见,我将通过值将structConfig传递给一个函数。在这个函数中,我需要引用该结构的一些字段,并且我对如何做有很大的麻烦。
use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
let config = new_config();
start(config).await.unwrap();
}
#[derive(Clone)]
pub struct Config { // never changes during the app life, it's a read only once created at runtime
pub app_name: String,
pub port: String,
}
fn new_config() -> Config {
Config {
app_name: String::from("APP_NAME"),
port: String::from("1234"),
}
}
pub struct AppState {
pub config: Config,
}
async fn hello() -> impl Responder {
HttpResponse::Ok()
}
async fn start(config: Config) -> std::io::Result<()> {
println!("{}", config.app_name); //I'm using it the first time here
let server = HttpServer::new(move || { // I'm moving it here
App::new()
.app_data(web::Data::new(AppState { config })) // here I get an error: cannot move out of `config`, a captured variable in an `Fn` closure. move occurs because `config` has type `Config`, which does not implement the `Copy` trait rustc E0507
.route(&config.app_name, web::get().to(hello))
});
let addr = SocketAddr::from(([127, 0, 0, 1], config.port.parse::<u16>().unwrap())); // here another error: borrow of moved value: `config`. borrow occurs due to deref coercion to `str` rustc E0382
server.bind(("127.0.0.1", 8080))?.run().await
}你能帮我理解用锈菌做这件事的惯用方法是什么吗?
发布于 2022-08-11 00:04:44
在这种情况下,由于不能保证Config值的生存期足够长,您可能需要的是通信线程安全共享值所有权的Arc<Config>。您可以克隆只复制句柄的Arc;仍然只有一个Config实例。例如:
pub struct AppState {
pub config: Arc<Config>,
}
async fn start(config: Config) -> std::io::Result<()> {
// Move the config into an Arc.
let config = Arc::new(config);
println!("{}", config.app_name);
// Get a second Arc for the same Config; this second Arc will be moved
// into the closure.
let config2 = Arc::clone(&config);
let server = HttpServer::new(move || {
// We clone the handle to create the AppState because we can't move
// out of a captured variable in an Fn closure.
App::new()
.app_data(web::Data::new(AppState { config: Arc::clone(&config2) }))
.route(&config2.app_name, web::get().to(hello))
});
let addr = SocketAddr::from(([127, 0, 0, 1], config.port.parse::<u16>().unwrap()));
server.bind(("127.0.0.1", 8080))?.run().await
}或者,您可以使用漏出一个箱子,这为您提供了一个'static引用。这适用于将在整个程序期间存活的数据,只要数据被彻底删除并不重要。(对于String值来说很好;当程序终止时,操作系统将清理分配)。
pub struct AppState {
pub config: &'static Config,
}
async fn start(config: Config) -> std::io::Result<()> {
// Move the config into a box, then leak it.
let config = Box::leak(Box::new(config));
println!("{}", config.app_name);
let server = HttpServer::new(|| {
App::new()
.app_data(web::Data::new(AppState { config }))
.route(&config.app_name, web::get().to(hello))
});
let addr = SocketAddr::from(([127, 0, 0, 1], config.port.parse::<u16>().unwrap()));
server.bind(("127.0.0.1", 8080))?.run().await
}Arc方法更干净,而泄漏盒方法更容易实现。
https://stackoverflow.com/questions/73313874
复制相似问题