如何使用Serde反序列化含字符串或字符串数组字段的JSON数据?
使用Serde反序列化支持字符串/字符串数组的JSON数据
你的JSON数据中,字段既可以是单个字符串,也可以是字符串数组,这种场景下可以通过两种方式实现Serde反序列化:
方法一:使用serde_with库的OneOrMany类型(推荐)
serde_with库提供了现成的OneOrMany类型,专门处理这种"单个值或数组"的情况,无需手动编写反序列化逻辑。
步骤1:添加依赖
在Cargo.toml中加入对应依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_with = "3.0"
步骤2:定义结构体
使用#[serde_as]属性标记结构体,字段类型指定为OneOrMany<String>,最终会统一解析为Vec<String>:
use serde::Deserialize; use serde_with::{serde_as, OneOrMany}; #[serde_as] #[derive(Debug, Deserialize)] struct MyData { #[serde_as(as = "OneOrMany<_>")] keya: Vec<String>, #[serde_as(as = "OneOrMany<_>")] keyb: Vec<String>, }
步骤3:反序列化示例
fn main() -> Result<(), serde_json::Error> { // 测试单个字符串的情况 let json1 = r#"{ "keya": "some string", "keyb": "some string" }"#; let data1: MyData = serde_json::from_str(json1)?; println!("{:?}", data1); // MyData { keya: ["some string"], keyb: ["some string"] } // 测试混合类型的情况 let json2 = r#"{ "keya": "some string", "keyb": ["some string", "some string"] }"#; let data2: MyData = serde_json::from_str(json2)?; println!("{:?}", data2); // MyData { keya: ["some string"], keyb: ["some string", "some string"] } // 另外两种数组+字符串、数组+数组的格式也可正常解析 Ok(()) }
方法二:自定义反序列化类型(不依赖额外库)
如果不想引入第三方库,可以手动实现支持两种类型的自定义结构体,并实现Deserialize trait。
步骤1:定义自定义类型与反序列化逻辑
use serde::de::{self, Deserializer, Visitor}; use serde::Deserialize; use std::fmt; #[derive(Debug)] struct StringOrArray(Vec<String>); struct StringOrArrayVisitor; impl<'de> Visitor<'de> for StringOrArrayVisitor { type Value = StringOrArray; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a string or an array of strings") } // 处理单个字符串 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: de::Error, { Ok(StringOrArray(vec![v.to_string()])) } // 处理字符串数组 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(s) = seq.next_element()? { vec.push(s); } Ok(StringOrArray(vec)) } } impl<'de> Deserialize<'de> for StringOrArray { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { deserializer.deserialize_any(StringOrArrayVisitor) } }
步骤2:在主结构体中使用
#[derive(Debug, Deserialize)] struct MyData { keya: StringOrArray, keyb: StringOrArray, }
使用时可通过keya.0访问内部的Vec<String>集合。
步骤3:测试反序列化
逻辑和方法一一致,四种JSON格式均可正常解析。
内容的提问来源于stack exchange,提问作者Happy Machine
相关产品推荐
相关产品推荐

