TOML 是一种简单、符合人体工程学且可读的配置格式;Rust 的包管理器cargo就使用 TOML 格式;本文介绍在 Rust 中如何来处理 TOML 格式的数据;

在 Rust中,可以使用toml库来解析和生成 TOML 格式的数据;联合serdetoml,可以将 TOML 字符串解析为任意 Rust 结构体,或将 Rust 结构体序列化为 TOML 格式的字符串。

添加依赖

要使用tomlserde,需添加依赖,编辑Cargo.toml文件,添加以下内容:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
toml = "0.9"

使用 toml 库

toml 库提供一个代表 TOML 表的结构体toml::Table,可以使用它来访问和操作 TOML 格式的数据;

pub type Table = Map<String, Value>;

其中,Value表示toml::Value,是一个代表 TOML 值的枚举:

pub enum Value {
    String(String),
    Integer(i64),
    Float(f64),
    Boolean(bool),
    Datetime(Datetime),
    Array(Array),
    Table(Table),
}

以下是一个简单的例子,演示了如何使用toml::Table操作 TOML 表:

use toml::{Table, Value};

fn main() {

    let mut table = Table::new();

    // 插入键值对
    table.insert("website".to_string(),Value::String("perfcode.com".to_string()));
    table.insert("total".to_string(),Value::Integer(100));
    table.insert("enabled".to_string(),Value::Boolean(true));

    // 获取键值对
    let website = table.get("website").unwrap().as_str().unwrap();
    let total = table.get("total").unwrap().as_integer().unwrap();
    let enabled = table.get("enabled").unwrap().as_bool().unwrap();

    println!("website: {}, total: {}, enabled: {}", website, total, enabled);

    // 遍历所有键值对
    for (key, value) in table.iter() {
        println!(" - {}: {:?}", key, value);
    }

    // 删除键值对
    let removed_value = table.remove("total");
    println!("removed value: {:?}", removed_value);
}

程序运行结果

website: perfcode.com, total: 100, enabled: true
 - enabled: Boolean(true)
 - total: Integer(100)
 - website: String("perfcode.com")
removed value: Some(Integer(100))

解析TOML文档

解析 TOML 文档最简单的方法是通过Table类型:

use toml::Table;

fn main(){

    let toml_text = r#"
        a = "perfcode.com"
        b = true
        [others]
        c = 3
    "#;

    let value = toml_text.parse::<Table>().unwrap();
    
    println!("{}\n{}\n{}",
        value["a"].as_str().unwrap(),
        value["b"].as_bool().unwrap(),
        value["others"]["c"].as_integer().unwrap(),
    );
}

程序运行结果

perfcode.com
true
3

使用 toml::from_str 函数

toml 库提供一个toml::from_str函数可将 TOML 文档解析(反序列化)成toml::Table类型;修改前一个例子:

use toml::Table;

fn main(){

    let toml_text = r#"
        a = "perfcode.com"
        b = true
        [others]
        c = 3
    "#;

    let value:Table = toml::from_str(&toml_text).unwrap();

    println!("{}\n{}\n{}",
        value["a"].as_str().unwrap(),
        value["b"].as_bool().unwrap(),
        value["others"]["c"].as_integer().unwrap(),
    );
}

使用 toml::to_string 函数

可以使用toml::to_string函数,将toml::Table类型序列化成 TOML 字符串:

use toml::Table;

fn main(){

    let toml_text = r#"
        a = "perfcode.com"
    "#;

    let mut value:Table = toml::from_str(&toml_text).unwrap();

    value.insert("b".to_string(),toml::Value::String("www.perfcode.com".to_string()));

    let new_toml = toml::to_string(&value).unwrap();

    println!("{}",new_toml);

}

程序运行结果

a = "perfcode.com"
b = "www.perfcode.com"

对自定义结构体序列化和反序列化

一个 TOML 反序列化的例子:

use serde::{Deserialize,Serialize};

#[derive(Deserialize,Serialize)]
struct Config {
    ip: String,
    port: u16,
    others: Others
}

#[derive(Deserialize,Serialize)]
struct Others {
    salt: String,
    use_whitelist: bool,
}

fn main(){

    let tom_text = r#"
        ip = "127.0.0.1"
        port = 80
        [others]
        salt = "xxxxxx"
        use_whitelist = false
    "#;

    let config:Config = toml::from_str(tom_text).unwrap();

    println!("ip: {}\nport: {}\nsalt: {}\nuse_whitelist: {}",
        config.ip,
        config.port,
        config.others.salt,
        config.others.use_whitelist
    );
}

程序运行结果

ip: 127.0.0.1
port: 80
salt: xxxxxx
use_whitelist: false

一个 TOML 序列化的例子:

use serde::{Deserialize,Serialize};

#[derive(Deserialize,Serialize)]
struct Config {
    ip: String,
    port: u16,
    others: Others
}

#[derive(Deserialize,Serialize)]
struct Others {
    salt: String,
    use_whitelist: bool,
}

fn main(){

    // 序列化
    let new_config = Config {
        ip: "0.0.0.0".to_string(),
        port: 80,
        others: Others {
            salt: "ssssssssss".to_string(),
            use_whitelist: true
        }
    };
    let new_toml = toml::to_string(&new_config).unwrap();
    
    println!("{}",new_toml);
    
}

程序运行结果

ip = "0.0.0.0"
port = 80

[others]
salt = "ssssssssss"
use_whitelist = true