rust实现解析yml配置

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云解析 DNS,旗舰版 1个月
简介: rust实现解析yml配置

任何项目都离不开对于配置文件的读取和解析,rust项目也一样。同样的,我们还是需要依赖第三方crate来帮助我们完成针对yml文件的读取和解析工作。

依赖

首先要做的就是引入第三方依赖:

[dependencies]
# 序列化工具
serde = { version = "1.0.140", features = ["derive"] }
serde_json = "1.0.75"
schemars = "0.8.8"
serde_yaml = "0.8.23"
# 初始化工具
lazy_static = "1.4.0"
复制代码

serdeserde_jsonschemars是用来做json序列化操作的;serde_yaml是用来解析yaml字符串的;

lazy_static是用来一次性初始化读取的配置,保持全局都是单例。

创建配置文件

我们在src目录同级创建application.yml和application-dev.yml:

application.yml

profiles:
  active: dev
复制代码

application-dev.yml

# mysql 配置
mysql:
  host: 127.0.0.1
  port: 3306
  username: root
  password: "123456"
  db_name: awesome_db
复制代码

创建配置对应的model

配置文件创建好后,借用面向对象的思想,我们应该要构造与之对应的数据模型,在rust中也就是struct:

use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct Profiles {
    pub active: String,
}
// 用来接收application.yml解析结果
#[derive(Serialize, Deserialize, Debug)]
pub struct EnvConfig {
    pub profiles: Profiles,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Mysql {
    pub host: String,
    pub port: u32,
    pub username: String,
    pub password: String,
    pub db_name: String,
}
// 用来接收application-dev.yml解析结果
#[derive(Serialize, Deserialize, Debug)]
pub struct GlobalConfig {
    // 解析对应的mysql配置
    pub mysql: Mysql,
    // 还可以添加其他需要解析的配置
}
复制代码

解析

我们前面已经把配置文件和对应的model都准备好了,下面最关键的就是如何把配置解析成指定的model:

// 加载指定配置文件
fn load_config<T>(path: &str) -> Option<T> where T: DeserializeOwned {
    // 1.通过std::fs读取配置文件内容
    // 2.通过serde_yaml解析读取到的yaml配置转换成json对象
    match serde_yaml::from_str::<RootSchema>(&std::fs::read_to_string(path).expect(&format!("failure read file {}", path))) {
        Ok(root_schema) => {
            // 通过serde_json把json对象转换指定的model
            let data = serde_json::to_string_pretty(&root_schema).expect("failure to parse RootSchema");
            let config = serde_json::from_str::<T>(&*data).expect(&format!("failure to format json str {}",&data));
            // 返回格式化结果
            Some(config)
        }
        Err(err) => {
            // 记录日志
            info!("{}",err);
            // 返回None
            None
        }
    }
}
复制代码

上面是一个抽象化的方法,也是最核心的方法。需要注意的是泛型对象得是DeserializeOwned,而不是Deserialize<'a>,原因在于serde_json::from_str::<T>()所需要的参数是一个有生命周期的参数,但是data在方法执行完毕后会被销毁掉,但是返回值并不是马上销毁,它还需要给外面的调用中使用,所以导致Deserialize<'a>解决不了问题,一直无法通过编译。DeserializeOwned就可以解决这种问题。

// 加载目标文件application.yml
fn load_env_config() -> Option<EnvConfig> {
    load_config::<EnvConfig>("application.yml")
}
// 根据环境加载application-{}.yml文件
fn load_global_config_from_env(active: String) -> Option<GlobalConfig> {
    let path = format!("application-{}.yml", active);
    load_config::<GlobalConfig>(&path)
}
// 真正对外暴露的方法,根据application.yml指定的环境变量动态加载对应的配置文件
pub fn load_global_config() -> Option<GlobalConfig> {
    if let Some(env_config) = load_env_config() {
        return load_global_config_from_env(env_config.profiles.active);
    }
    None
}
复制代码

测试

为了测试我们的代码是否能正常运行,我们编写一些简单的测试用例:

#[cfg(test)]
mod test {
    use crate::load_config::init_load_config::load_global_config;
    use crate::load_config::models::GlobalConfig;
    #[test]
    pub fn load_config_test() {
        match load_global_config() {
            None => {
                println!("None");
            }
            Some(config) => {
                println!("{:#?}", config);
            }
        }
    }
}
复制代码

输出结果如下:

Finished test [unoptimized + debuginfo] target(s) in 1.08s
Running unittests src/main.rs (target/debug/deps/hello_salvo-b9ecf8dc1aa86991)
GlobalConfig {
    mysql: Mysql {
        host: "127.0.0.1",
        port: 3306,
        username: "root",
        password: "123456",
        db_name: "awesome_db",
    },
}
复制代码

单例化

为了能在项目中使用咱们上面已经实现的全局配置参数,我们需要对它做一次初始化操作。也就是在整个项目中,只加载一次该配置:

use lazy_static::lazy_static;
use crate::load_config::init_load_config;
use crate::load_config::models::GlobalConfig;
lazy_static! {
    pub static ref GLOBAL_CONFIG:GlobalConfig=init_load_config::load_global_config().unwrap();
}
复制代码

通过lazy_static的宏来控制配置文件一次性载入后,在项目中只需要直接使用即可。

main函数使用

fn main() {
    let config = &GLOBAL_CONFIG;
    println!("{:?}", config.mysql);
}
复制代码

在main函数中,可以直接使用已经初始化成功后的GLOBAL_CONFIG了。

至此,我们使用rust解析yml配置文件就完成了。


相关文章
|
1月前
|
域名解析 存储 缓存
DNS是什么?内网电脑需要配置吗?
【10月更文挑战第22天】DNS是什么?内网电脑需要配置吗?
117 1
|
2月前
|
机器学习/深度学习 调度
mmseg配置解析 Polynomial Decay 多项式衰减
Polynomial Decay(多项式衰减)是一种常用的学习率调度方法,通过多项式函数逐步减少学习率,帮助模型更好地收敛。公式为:\[ lr = (lr_{initial} - \eta_{min}) \times \left(1 - \frac{current\_iter}{max\_iters}\right)^{power} + \eta_{min} \]。参数包括初始学习率、最小学习率、当前迭代次数、总迭代次数和衰减指数。适用于需要平滑降低学习率的场景,特别在训练后期微调模型参数。
65 0
mmseg配置解析 Polynomial Decay 多项式衰减
|
2月前
|
网络协议 Docker 容器
docker中的DNS配置
【10月更文挑战第5天】
348 1
|
2月前
|
弹性计算 网络协议 Ubuntu
如何在阿里云国际版Linux云服务器中自定义配置DNS
如何在阿里云国际版Linux云服务器中自定义配置DNS
|
2月前
|
JSON JavaScript 前端开发
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
88 0
|
2月前
|
编解码 计算机视觉
mmseg配置解析 align_corners=False
`align_corners=False` 是图像插值操作中的一个参数,影响输入和输出图像的角点对齐方式。`align_corners=True` 严格对齐角点,而 `align_corners=False` 均匀分布像素点,更适用于保持整体比例关系的任务,如语义分割。
35 0
|
2月前
|
机器学习/深度学习 编解码
mmseg配置解析 contract_dilation=True
`contract_dilation=True` 是 ResNetV1c 中的一种设置,用于解决多层膨胀卷积中的“栅格效应”。通过调整膨胀率,使卷积核在不同阶段更密集地覆盖输入特征图,避免信息丢失,提升特征提取质量,尤其在语义分割任务中效果显著。
44 0
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于注解配置的程序--源码解析
手动开发-简单的Spring基于注解配置的程序--源码解析
47 0
|
2月前
|
XML Java 数据格式
手动开发-简单的Spring基于XML配置的程序--源码解析
手动开发-简单的Spring基于XML配置的程序--源码解析
82 0
|
4月前
|
Rust JavaScript 前端开发
Rust! 无VDom! 尤雨溪解析 Vue.js 2024 新特性
Rust! 无VDom! 尤雨溪解析 Vue.js 2024 新特性

推荐镜像

更多
下一篇
无影云桌面