rust实现解析yml配置

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,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配置文件就完成了。


相关文章
|
29天前
|
数据采集 消息中间件 监控
Flume数据采集系统设计与配置实战:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入探讨Apache Flume的数据采集系统设计,涵盖Flume Agent、Source、Channel、Sink的核心概念及其配置实战。通过实例展示了文件日志收集、网络数据接收、命令行实时数据捕获等场景。此外,还讨论了Flume与同类工具的对比、实际项目挑战及解决方案,以及未来发展趋势。提供配置示例帮助理解Flume在数据集成、日志收集中的应用,为面试准备提供扎实的理论与实践支持。
35 1
|
2月前
|
缓存 网络协议 Linux
【Shell 命令集合 网络通讯 】Linux 配置DNS dnsconf 命令 使用教程
【Shell 命令集合 网络通讯 】Linux 配置DNS dnsconf 命令 使用教程
45 0
|
5天前
|
缓存 测试技术 Android开发
深入了解Appium:Capability 高级配置技巧解析
Appium 提供多种进阶配置项以优化自动化测试,如 deviceName 作为设备别名,udid 确保选择特定设备,newCommandTimeout 设置超时时间,PRINT_PAGE_SOURCE_ON_FIND_FAILURE 在错误时打印页面源,以及测试策略中的 noReset、shouldTerminateApp 和 forceAppLaunch 控制应用状态和重启。这些配置可提升测试效率和准确性。
16 2
|
6天前
|
存储 弹性计算 固态存储
阿里云服务器配置选择指南,2024年全解析
阿里云服务器配置选择涉及CPU、内存、带宽和磁盘。个人开发者或中小企业推荐使用轻量应用服务器或ECS经济型实例,如2核2G3M配置,适合网站和轻量应用。企业用户则应选择企业级独享型ECS,如计算型c7、通用型g7,至少2核4G起,带宽建议5M,系统盘考虑SSD云盘或ESSD云盘以保证性能。阿里云提供了多种实例类型和配置,用户需根据实际需求进行选择。
|
11天前
|
分布式计算 DataWorks 调度
DataWorks操作报错合集之DataWorks配置参数在开发环境进行调度,参数解析不出来,收到了 "Table does not exist" 的错误,该怎么处理
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
24 0
|
12天前
|
分布式计算 大数据 数据处理
MaxCompute操作报错合集之在开发环境中配置MaxCompute参数进行调度,但参数解析不出来,如何解决
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
14天前
|
监控 安全 网络协议
|
16天前
|
分布式计算 网络协议 Hadoop
Hadoop节点扩展配置DNS和主机名解析
【4月更文挑战第19天】
22 1
|
18天前
|
网络协议 Linux 网络安全
Centos7 配置DNS服务
该教程指导配置DNS服务器:首先通过yum安装bind和cach件,然后修改IP设置。接着,编辑/etc/named.conf,将第13行和21行的参数改为&quot;any&quot;。在/etc/named.rfc1912中更新正向和反向域名。创建正向解析文件/var/named.localhost和反向解析文件/var/named.loopback,按指定格式添加解析记录。最后,重启服务,确保防火墙关闭,通过nslookup检查DNS配置效果。
25 1
|
18天前
|
Rust 安全 程序员
Rust vs Go:解析两者的独特特性和适用场景
在讨论 Rust 与 Go 两种编程语言哪种更优秀时,我们将探讨它们在性能、简易性、安全性、功能、规模和并发处理等方面的比较。同时,我们看看它们有什么共同点和根本的差异。现在就来看看这个友好而公平的对比。

推荐镜像

更多