首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在同一个函数中多次使用只读结构字段的惯用方式是什么?

在同一个函数中多次使用只读结构字段的惯用方式是什么?
EN

Stack Overflow用户
提问于 2022-08-10 23:50:59
回答 1查看 153关注 0票数 1

我只是从锈病开始,因为我是一个通过学习来学习的人,我想要完全理解在铁锈里解决这种案件的惯用方法。

我在聊天中得到的许多回复都是一样的:“克隆人!”

我不想clone(),我在这里学习更好的方法,否则我将回到使用Golang或Javascript。

另外,我害怕克隆,因为在这种情况下,我不想分配相同的数据(Config)多次。

即使我与许多工作人员一起工作(actix就是这种情况),我也希望使用对该结构的引用,而不是每次分配相同数据的时候都克隆。我说错了吗?

在下面的简单代码中,如您所见,我将通过值将structConfig传递给一个函数。在这个函数中,我需要引用该结构的一些字段,并且我对如何做有很大的麻烦。

  • main.rs:
代码语言:javascript
运行
复制
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
}

你能帮我理解用锈菌做这件事的惯用方法是什么吗?

EN

Stack Overflow用户

回答已采纳

发布于 2022-08-11 00:04:44

在这种情况下,由于不能保证Config值的生存期足够长,您可能需要的是通信线程安全共享值所有权的Arc<Config>。您可以克隆只复制句柄的Arc;仍然只有一个Config实例。例如:

代码语言:javascript
运行
复制
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值来说很好;当程序终止时,操作系统将清理分配)。

代码语言:javascript
运行
复制
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方法更干净,而泄漏盒方法更容易实现。

票数 4
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73313874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档