You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Serde读取TOML文件:camelCase与snake_case映射问题

问题:Rust中config crate结合serde实现camelCase到snake_case反序列化失败

我刚接触Rust,正在学习如何在Rust中读取配置。尝试使用config crate结合serde将配置反序列化为结构体:

use config::{Config, File};
use serde::Deserialize;

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct DatabaseConfiguration {
  connection_string: String
}

#[derive(Deserialize)]
struct Configuration {
    database: DatabaseConfiguration
}

fn main() {
    println!("Hello, world!");
    let settings = Config::builder()
        .add_source(File::with_name("config"))
        .build()
        .unwrap();
    let config: Configuration = settings.try_deserialize().unwrap();
    println!("Configured settings:");
    println!("connection string: {:?}", config.database.connection_string);
}

对应的TOML文件内容如下:

[database]
connectionString = "https://awesome"

根据Serde文档的理解,rename_all = "camelCase"应能将TOML中的connectionString映射到结构体的connection_string,但反序列化时报错:

missing field `connection_string`

将TOML属性改为snake_case并移除rename_all配置后可正常运行,显然我对Serde容器属性的用法存在误解,请问该如何正确实现这一需求?


解决方案

问题出在config crate的默认行为:它会自动将所有配置键标准化为snake_case,也就是说TOML中的connectionString会被转换成connection_string后再传给serde。而你添加的#[serde(rename_all = "camelCase")]会让serde期望输入的键是camelCase格式(即connectionString),两者不匹配导致报错。

有两种可行的解决方式:

方式一:禁用config的键标准化

让config保留原始的键名格式,交给serde处理映射。只需在构建Config时设置命名规范为None:

use config::{Config, File, NamingConvention};
use serde::Deserialize;

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct DatabaseConfiguration {
  connection_string: String
}

#[derive(Deserialize)]
struct Configuration {
    database: DatabaseConfiguration
}

fn main() {
    println!("Hello, world!");
    let settings = Config::builder()
        .set_naming_convention(NamingConvention::None) // 禁用键标准化
        .add_source(File::with_name("config"))
        .build()
        .unwrap();
    let config: Configuration = settings.try_deserialize().unwrap();
    println!("Configured settings:");
    println!("connection string: {:?}", config.database.connection_string);
}

方式二:利用config的默认转换简化代码

既然config已经自动将camelCase转换为snake_case,直接去掉结构体上的rename_all属性即可,无需额外配置:

use config::{Config, File};
use serde::Deserialize;

#[derive(Deserialize)]
struct DatabaseConfiguration {
  connection_string: String
}

#[derive(Deserialize)]
struct Configuration {
    database: DatabaseConfiguration
}

fn main() {
    println!("Hello, world!");
    let settings = Config::builder()
        .add_source(File::with_name("config"))
        .build()
        .unwrap();
    let config: Configuration = settings.try_deserialize().unwrap();
    println!("Configured settings:");
    println!("connection string: {:?}", config.database.connection_string);
}

如果需要同时兼容其他序列化场景(比如直接用serde解析TOML字符串),推荐使用方式一;如果仅使用config crate读取配置,方式二更简洁。


内容的提问来源于stack exchange,提问作者flq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:32:13