Rust中Serde实现二进制与JSON双向序列化适配问题
解决方案:利用Serde的
is_human_readable()区分序列化场景 你的核心需求是让path字段在二进制(bincode)和JSON序列化/反序列化时表现不同:二进制保留原始字节,JSON转为可读字符串。不需要复杂的自定义类型判断,Serde内置的is_human_readable()方法可以直接区分两种场景,下面是具体实现方案:
1. 基础依赖配置
确保Cargo.toml包含所需依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } bincode = "2.0" serde_json = "1.0" encoding = "0.2"
2. 自定义序列化/反序列化函数
编写针对Vec<u8>的处理函数,通过is_human_readable()判断当前序列化场景:
use encoding::{all::GBK, Encoding, DecoderTrap, EncoderTrap}; use serde::{Serialize, Deserialize, Serializer, Deserializer}; // 序列化path字段:JSON转字符串,二进制保留原始字节 fn serialize_path<S>(path: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { if serializer.is_human_readable() { // JSON场景:解码GBK字节为字符串 let str_val = GBK.decode(path, DecoderTrap::Strict) .map_err(|e| serde::ser::Error::custom(format!("GBK解码失败: {}", e)))?; serializer.serialize_str(&str_val) } else { // 二进制场景:直接序列化原始字节 serializer.serialize_bytes(path) } } // 反序列化path字段:JSON转GBK字节,二进制读取原始字节 fn deserialize_path<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error> where D: Deserializer<'de>, { if deserializer.is_human_readable() { // JSON场景:编码字符串为GBK字节 let str_val = String::deserialize(deserializer)?; GBK.encode(&str_val, EncoderTrap::Strict) .map_err(|e| serde::de::Error::custom(format!("GBK编码失败: {}", e))) } else { // 二进制场景:直接读取原始字节 Vec::<u8>::deserialize(deserializer) } }
3. 修改结构体定义
给path字段添加Serde属性,指定使用上述自定义函数:
#[derive(Serialize, Deserialize, Debug)] pub(crate) struct Item { pub id: u32, #[serde(serialize_with = "serialize_path", deserialize_with = "deserialize_path")] pub path: Vec<u8>, } // 保留原有辅助方法(可选) impl Item { pub fn path_as_str(&self) -> String { GBK.decode(self.path.as_slice(), DecoderTrap::Strict).unwrap() } }
4. 双向转换测试
验证二进制和JSON的序列化/反序列化是否正常工作:
fn main() -> Result<(), Box<dyn std::error::Error>> { // 测试数据:GBK编码的"测试路径"字节 let test_path = GBK.encode("测试路径", EncoderTrap::Strict)?; let item = Item { id: 1, path: test_path }; // JSON序列化与反序列化 let json_str = serde_json::to_string_pretty(&item)?; println!("JSON输出:\n{}", json_str); let item_from_json: Item = serde_json::from_str(&json_str)?; assert_eq!(item.id, item_from_json.id); assert_eq!(item.path, item_from_json.path); // 二进制序列化与反序列化 let binary_data = bincode::serialize(&item)?; println!("二进制数据长度: {}字节", binary_data.len()); let item_from_binary: Item = bincode::deserialize(&binary_data)?; assert_eq!(item.id, item_from_binary.id); assert_eq!(item.path, item_from_binary.path); Ok(()) }
可选:自定义WString类型实现
如果坚持使用自定义类型封装,修改后的实现同样基于is_human_readable()判断:
use std::fmt; use std::ops::Deref; use encoding::{all::GBK, Encoding, DecoderTrap, EncoderTrap}; use serde::{Serialize, Deserialize, Serializer, de::{self, Visitor}, Deserializer}; #[derive(Debug, Clone, PartialEq)] pub struct WString(Vec<u8>); impl Serialize for WString { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { if serializer.is_human_readable() { let str_val = GBK.decode(&self.0, DecoderTrap::Strict) .map_err(|e| serde::ser::Error::custom(format!("GBK解码失败: {}", e)))?; serializer.serialize_str(&str_val) } else { serializer.serialize_bytes(&self.0) } } } impl<'de> Deserialize<'de> for WString { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { if deserializer.is_human_readable() { let str_val = String::deserialize(deserializer)?; let bytes = GBK.encode(&str_val, EncoderTrap::Strict) .map_err(|e| serde::de::Error::custom(format!("GBK编码失败: {}", e)))?; Ok(WString(bytes)) } else { let bytes = Vec::<u8>::deserialize(deserializer)?; Ok(WString(bytes)) } } } // 方便从String创建WString impl From<String> for WString { fn from(s: String) -> Self { let bytes = GBK.encode(&s, EncoderTrap::Strict).unwrap(); WString(bytes) } } // 方便直接访问内部Vec<u8> impl Deref for WString { type Target = Vec<u8>; fn deref(&self) -> &Self::Target { &self.0 } }
对应的结构体修改为:
#[derive(Serialize, Deserialize, Debug)] pub(crate) struct Item { pub id: u32, pub path: WString, }
内容的提问来源于stack exchange,提问作者Leo Letto
相关产品推荐
相关产品推荐

