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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 09:52:46