如何使用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,用派生宏一键完成:
- 先在Cargo.toml添加依赖:
serde_tuple = "0.6" serde = { version = "1.0", features = ["derive"] } serde_bytes = "0.11"
- 结构体直接加对应派生即可:
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
相关产品推荐
相关产品推荐

