如何将ArrayOfTables序列化为InlineTables?(Rust toml/toml_edit)
问题描述
我定义了如下Rust结构体:
#[derive(Serialize, Deserialize)] pub struct TestItem { pub a: String, pub b: String, } #[derive(Serialize, Deserialize)] pub struct Test { pub items: Vec<TestItem>, }
使用toml crate默认序列化会生成**数组表(ArrayOfTables)**格式:
[[items]] a = "testa1" b = "testb1" # etc
但我需要将items序列化为**数组内嵌表(Array of Inline Tables)**格式以提升可读性:
items = [ { a = "testa1", b = "testb1" }, # etc ]
尝试参考相关示例,但由于items被识别为ArrayOfTables,常规方法无法生效,自己编写的TestVisitor会跳过ArrayOfTables内的Table,无法完成格式转换,请问如何编写符合需求的Visitor?
解决方案
不需要复杂的Visitor实现,通过自定义Serialize trait逻辑或使用toml_edit库手动构建文档,就能实现目标格式。以下是两种可行方案:
方案一:自定义Serialize实现
直接为结构体手动实现Serialize,强制将Vec<TestItem>序列化为内嵌表数组:
use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; use serde::Deserialize; #[derive(Deserialize)] pub struct TestItem { pub a: String, pub b: String, } #[derive(Deserialize)] pub struct Test { pub items: Vec<TestItem>, } impl Serialize for TestItem { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { // 将TestItem序列化为内嵌表结构 let mut table = serializer.serialize_struct("TestItem", 2)?; table.serialize_field("a", &self.a)?; table.serialize_field("b", &self.b)?; table.end() } } impl Serialize for Test { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut state = serializer.serialize_struct("Test", 1)?; // 关键:将items按普通数组序列化,而非数组表 state.serialize_field("items", &self.items)?; state.end() } }
使用toml::to_string(&test)序列化时,会自动生成内嵌表数组格式。
方案二:使用toml_edit手动构建文档
如果需要更灵活的格式控制(比如添加注释、调整缩进),可以用toml_edit直接操作AST:
use toml_edit::{Document, InlineTable, Value}; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] pub struct TestItem { pub a: String, pub b: String, } #[derive(Serialize, Deserialize)] pub struct Test { pub items: Vec<TestItem>, } fn test_to_toml(test: &Test) -> String { let mut doc = Document::new(); // 构建内嵌表数组 let mut items_array = toml_edit::Array::new(); for item in &test.items { let mut inline_table = InlineTable::new(); inline_table.insert("a", Value::from(item.a.clone())); inline_table.insert("b", Value::from(item.b.clone())); items_array.push(Value::InlineTable(inline_table)); } // 将数组添加到文档根节点 doc.insert("items", Value::Array(items_array)); // 格式化输出 doc.to_string() }
调用test_to_toml(&test)即可生成符合要求的TOML格式。
原理说明
toml crate默认将Vec<struct>序列化为数组表([[items]]),这是因为TOML规范中数组表用于表示一组独立表的集合;而内嵌表数组是数组元素为内嵌表的结构。通过自定义Serialize实现,我们强制序列化器将Vec<TestItem>识别为普通数组,每个元素按内嵌表序列化,从而绕过默认的数组表逻辑。
内容的提问来源于stack exchange,提问作者will-hart
相关产品推荐
相关产品推荐

