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

如何将十六进制序列反序列化为Option<Vec<ObjectId>>?

解决方案

要实现将十六进制序列反序列化为Option<Vec<ObjectId>>(空数组返回None,非空数组返回Some(Vec<ObjectId>)),可以通过自定义Serde Visitor来完成。以下是完整的实现代码及使用示例:

完整代码实现

首先导入必要的依赖包:

use bson::oid::ObjectId;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;

1. 自定义Visitor实现反序列化逻辑

这个Visitor会遍历输入的数组序列,将每个十六进制字符串转换为ObjectId,最后根据收集到的数组是否为空返回None或Some(Vec<ObjectId>):

struct OptionObjectIdVecVisitor;

impl<'de> de::Visitor<'de> for OptionObjectIdVecVisitor {
    type Value = Option<Vec<ObjectId>>;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("JSON数组,元素为表示ObjectId的十六进制字符串")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: de::SeqAccess<'de>,
    {
        // 预分配内存提升性能
        let mut oids = Vec::with_capacity(seq.size_hint().unwrap_or(0));

        while let Some(hex_str) = seq.next_element::<String>()? {
            // 解析十六进制字符串为ObjectId,失败时返回自定义错误
            let oid = ObjectId::parse_str(&hex_str)
                .map_err(|e| de::Error::custom(format!("无效的ObjectId格式: {}", e)))?;
            oids.push(oid);
        }

        // 空数组返回None,非空返回Some(Vec)
        Ok(if oids.is_empty() { None } else { Some(oids) })
    }
}

2. 封装反序列化函数

将Visitor逻辑封装为可通过#[serde(deserialize_with)]调用的函数:

pub fn deserialize_option_object_id_vec<'de, D>(deserializer: D) -> Result<Option<Vec<ObjectId>>, D::Error>
where
    D: Deserializer<'de>,
{
    deserializer.deserialize_seq(OptionObjectIdVecVisitor)
}

3. 配套序列化函数(与反序列化对称)

如果需要序列化时将None转为空数组、Some(Vec)转为非空数组,可以实现对应的序列化函数:

pub fn serialize_option_object_id_vec<S>(ids: &Option<Vec<ObjectId>>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    match ids {
        Some(oids) => {
            let hex_strs: Vec<String> = oids.iter().map(|oid| oid.to_hex()).collect();
            serializer.serialize_seq(hex_strs.into_iter())
        }
        None => serializer.serialize_seq(None),
    }
}

使用示例

通过Serde的属性将自定义序列化/反序列化逻辑应用到结构体字段:

#[derive(Debug, Serialize, Deserialize)]
struct Data {
    #[serde(
        serialize_with = "serialize_option_object_id_vec",
        deserialize_with = "deserialize_option_object_id_vec"
    )]
    object_ids: Option<Vec<ObjectId>>,
}

// 测试非空数组输入
fn test_non_empty() {
    let json = r#"{"object_ids": ["6397f513d5e4a64eda84aa37", "6397f513d5e4a64eda84aa39"]}"#;
    let data: Data = serde_json::from_str(json).unwrap();
    
    assert!(data.object_ids.is_some());
    let oids = data.object_ids.unwrap();
    assert_eq!(oids.len(), 2);
    assert_eq!(oids[0].to_hex(), "6397f513d5e4a64eda84aa37");
}

// 测试空数组输入
fn test_empty() {
    let json = r#"{"object_ids": []}"#;
    let data: Data = serde_json::from_str(json).unwrap();
    
    assert!(data.object_ids.is_none());
}

关键点说明

  • Visitor核心逻辑:visit_seq方法负责遍历输入序列,逐个解析十六进制字符串为ObjectId,最后根据数组是否为空决定返回None还是Some。
  • 错误处理:将ObjectId解析失败的错误转换为Serde的自定义错误,确保错误信息清晰。
  • 性能优化:通过seq.size_hint()预分配Vec内存,减少内存分配次数。
  • 对称序列化:序列化函数保证None序列化为空数组,与反序列化逻辑形成对称,确保数据往返一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:40:40