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工具类型可直接适配单个值/数组的反序列化场景,无需手动编写复杂逻辑。
- 添加依赖到
Cargo.toml:
serde_with = "3.0"
- 修改结构体定义:
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
相关产品推荐
相关产品推荐

