【发布时间】:2021-07-29 16:38:07
【问题描述】:
我有以下 Rust 代码,它模拟了一个配置文件,其中包括一个 HashMap 与一个 enum 键控。
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
enum Source {
#[serde(rename = "foo")]
Foo,
#[serde(rename = "bar")]
Bar
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct SourceDetails {
name: String,
address: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct Config {
name: String,
main_source: Source,
sources: HashMap<Source, SourceDetails>,
}
fn main() {
let config_str = std::fs::read_to_string("testdata.toml").unwrap();
match toml::from_str::<Config>(&config_str) {
Ok(config) => println!("toml: {:?}", config),
Err(err) => eprintln!("toml: {:?}", err),
}
let config_str = std::fs::read_to_string("testdata.json").unwrap();
match serde_json::from_str::<Config>(&config_str) {
Ok(config) => println!("json: {:?}", config),
Err(err) => eprintln!("json: {:?}", err),
}
}
这是 Toml 表示:
name = "big test"
main_source = "foo"
[sources]
foo = { name = "fooname", address = "fooaddr" }
[sources.bar]
name = "barname"
address = "baraddr"
这是 JSON 表示:
{
"name": "big test",
"main_source": "foo",
"sources": {
"foo": {
"name": "fooname",
"address": "fooaddr"
},
"bar": {
"name": "barname",
"address": "baraddr"
}
}
}
使用 serde_json 反序列化 JSON 效果很好,但使用 toml 反序列化 Toml 会出现错误。
Error: Error { inner: ErrorInner { kind: Custom, line: Some(5), col: 0, at: Some(77), message: "invalid type: string \"foo\", expected enum Source", key: ["sources"] } }
如果我将 sources HashMap 更改为键入 String 而不是 Source,则 JSON 和 Toml 都将正确反序列化。
我对 serde 和 toml 还很陌生,所以我正在寻找有关如何正确反序列化 toml 变体的建议。
【问题讨论】:
-
TOML 格式仅支持字符串作为键。正因为如此,
toml-rs库仅支持字符串键,但您有一个Source枚举作为键,这不是有效的 TOML:github.com/alexcrichton/toml-rs/issues/212 -
@SvetlinZarev 我发现不支持这种用法令人失望,因为 JSON 键也是按定义定义的字符串并且它们能够支持枚举。至少在那个问题中提供了一个合理的解决方法。