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

Rust中使用Serde自定义反序列化字符串Vec的问题

问题:JSON多格式字段反序列化为Rust结构体

需要将JSON中comments字段的两种格式:

  • 数组形式:"comments": ["string"]
  • 单个字符串形式:"comments": "string"

反序列化为如下Rust结构体:

#[derive(Debug, serde::Deserialize)]
pub struct Block {
    pub comments: Vec<String>, // 注:原代码中`Comments`需为可容纳多值的类型,这里以`Vec<String>`为例
}

当前使用的自定义反序列化函数仅能处理单个值转数组的场景,无法识别数组输入:

pub fn deserialize_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
    D: serde::Deserializer<'de>,
    T: serde::Deserialize<'de>,
{
    let s:T = serde::Deserialize::deserialize(deserializer)?; // 无法判断输入是数组还是单个值
    Ok(vec![s])
}

解决方案

方案1:使用serde_with库(简便推荐)

serde_with提供的OneOrMany工具类型可直接适配单个值/数组的反序列化场景,无需手动编写复杂逻辑。

  1. 添加依赖到Cargo.toml:
serde_with = "3.0"
  1. 修改结构体定义:
use serde_with::OneOrMany;

#[derive(Debug, serde::Deserialize)]
pub struct Block {
    #[serde(with = "OneOrMany")]
    pub comments: Vec<String>,
}

方案2:手动实现自定义反序列化

若不想引入第三方库,可通过Serde的Visitor模式实现类型判断:

use serde::{Deserialize, Deserializer, de::{self, Visitor}};
use std::fmt;

// 自定义反序列化函数,支持单个值或数组转为Vec
pub fn deserialize_one_or_many<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
    D: Deserializer<'de>,
    T: Deserialize<'de>,
{
    // 定义Visitor处理不同类型输入
    struct OneOrManyVisitor<T>(std::marker::PhantomData<T>);

    impl<'de, T> Visitor<'de> for OneOrManyVisitor<T>
    where
        T: Deserialize<'de>,
    {
        type Value = Vec<T>;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("单个值或值的数组")
        }

        // 处理数组输入
        fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
        where
            A: de::SeqAccess<'de>,
        {
            let mut vec = Vec::new();
            while let Some(item) = seq.next_element()? {
                vec.push(item);
            }
            Ok(vec)
        }

        // 处理字符串字面量输入
        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
            Ok(vec![T::deserialize(de::value::StrDeserializer::new(v))?])
        }

        // 处理带所有权的字符串输入
        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
        where
            E: de::Error,
        {
            Ok(vec![T::deserialize(de::value::StringDeserializer::new(v))?])
        }
    }

    // 触发Visitor匹配对应输入类型
    deserializer.deserialize_any(OneOrManyVisitor(std::marker::PhantomData))
}

// 在结构体中应用自定义反序列化函数
#[derive(Debug, serde::Deserialize)]
pub struct Block {
    #[serde(deserialize_with = "deserialize_one_or_many")]
    pub comments: Vec<String>,
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 08:55:31