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

如何将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 01:45:12