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

如何使用serde_json、ciborium实现Rust struct与无键数组的双向序列化

Rust Struct 按字段顺序序列化/反序列化为数组(无键)的实现方法

以下两种方案均完全兼容serde_json、ciborium等所有serde生态库,同时支持serde_bytes的高效字节数组处理,无需手动解析Value枚举。


方案1:手动实现serde的Serialize/Deserialize(无额外依赖)

不需要引入第三方crate,直接基于serde原生的元组序列化能力实现:

use serde::{Serialize, Deserialize};
use serde_bytes;

#[derive(Debug, PartialEq)]
struct Foo {
    a: String,
    b: u128,
    c: f64,
    #[serde(with = "serde_bytes")]
    d: Vec<u8>,
}

impl Serialize for Foo {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        // 按字段声明顺序组成元组序列化,自动输出为数组格式
        (
            &self.a,
            &self.b,
            &self.c,
            serde_bytes::Bytes::new(&self.d),
        ).serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Foo {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        // 按相同顺序反序列化元组,再转为struct
        let (a, b, c, d): (String, u128, f64, serde_bytes::ByteBuf) = 
            Deserialize::deserialize(deserializer)?;
        Ok(Self {
            a,
            b,
            c,
            d: d.into_vec(),
        })
    }
}

方案2:使用serde_tuple派生宏(最少代码量)

如果不想手动写实现,可以引入serde_tuple crate,用派生宏一键完成:

  1. 先在Cargo.toml添加依赖:
serde_tuple = "0.6"
serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11"
  1. 结构体直接加对应派生即可:
use serde::{Serialize, Deserialize};
use serde_tuple::{SerializeTuple, DeserializeTuple};
use serde_bytes;

#[derive(Debug, PartialEq, SerializeTuple, DeserializeTuple)]
struct Foo {
    a: String,
    b: u128,
    c: f64,
    #[serde(with = "serde_bytes")]
    d: Vec<u8>,
}

直接正常调用serde的序列化/反序列化方法即可,输出就是你需要的数组格式:

let foo = Foo {
    a: "string1".to_string(),
    b: 1,
    c: 1.1,
    d: vec![4, 34, 4, 4],
};
// serde_json序列化验证
let json = serde_json::to_string(&foo)?;
assert_eq!(json, r#"["string1",1,1.1,[4,34,4,4]]"#);
// ciborium序列化CBOR格式同样生效
let mut cbor_bytes = vec![];
ciborium::ser::into_writer(&foo, &mut cbor_bytes)?;

注意事项

  • 两种方案都严格依赖字段的声明顺序,调整字段顺序会导致序列化/反序列化不兼容,你已经明确不会变更字段顺序,所以没有问题。
  • 所有serde的字段属性(比如#[serde(default)]、#[serde(skip)]等)都可以正常使用,和普通serde派生的用法完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 09:27:02