處理配置檔案是應用開發的常規操作。成熟的開發語言都有自己處理配置檔案的套路。golang 有 viper 這樣的成熟第三方庫來處理配置檔案。rust 的第三方庫並不成熟。
這篇文章我們來聊聊 rust 如何處理配置檔案。
處理yaml配置檔案的流程
配置檔案的作用是一系列應用程式相應功能的開關。在應用啟動前配置,應用啟動時載入,以備執行時使用。
我們依舊用[interactcli-rs](https://github.com/jiashiwen/interactcli-rs) 為例,說明一下配置檔案的處理過程。
解析配置檔案的主要邏輯在 src/configure 目錄。
首先,定義一個結構體用來承載配置項。由於 Config struct 需要與yaml檔案互動,我們定義一個具備序列化與反序列化能力的結構體。
```rust#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]pub struct Config { pub server: String, pub token: String,}```
```rust
impl Config {
pub fn default() -> Self {
Self {
server: "http://127.0.0.1:8080".to_string(),
token: "".to_string(),
}
}
pub fn set_self(&mut self, config: Config) {
self.server = config.server;
self.token = config.token;
}
pub fn get_config_image(&self) -> Self {
self.clone()
}
pub fn flush_to_file(&self, path: String) -> Result<()> {
let yml = serde_yaml::to_string(&self)?;
fs::write(path, yml)?;
Ok(())
}
}
```
```rustlazy_static::lazy_static! { static ref GLOBAL_CONFIG: Mutex<Config> = { let global_config = Config::default(); Mutex::new(global_config) }; static ref CONFIG_FILE_PATH: RwLock<String> = RwLock::new({ let path = "".to_string(); path });}```
[interactcli-rs](https://github.com/jiashiwen/interactcli-rs) 是一個命令列程式。載入配置檔案的策略為:當指定配置檔案位置時,則按給定路徑載入配置;如果未指定配置檔案則按照預設路徑載入,此時若預設配置檔案不存在則終止程式。
src/cmd/rootcmd.rs 中的 cmd_match 函式包含上面的邏輯。
```rustfn cmd_match(matches: &ArgMatches) { if let Some(c) = matches.value_of("config") { set_config_file_path(c.to_string()); set_config_from_file(&get_config_file_path()); } else { set_config_from_file(""); } ......```
後記
手工處理配置檔案還是比較繁瑣。尤其在配置檔案的書寫上,必須明確配置每一個配置項,即使配置項為空也需填寫。為了保證配置檔案的配置項齊全,我們為Config struct 定義了 flush_to_file 函式,用來生成配置檔案。
由於rust的生態較 golang 以及 java 的生態還很年輕,第三方的工具包不及兩者完善。在配置檔案的處理上比較繁瑣,很多地方需要手工處理,但是已基本滿足要求。
我們們下期見。