如何使用Serde将含空对象值的JSON映射反序列化为字符串向量并实现反向序列化?
To solve this problem, we need to create a custom serialization/deserialization logic using Serde to convert between a JSON object with empty object values and a Vec<String> in Rust, while maintaining round-trip compatibility. Here's a step-by-step implementation:
Step 1: Add Dependencies
First, ensure your Cargo.toml includes the required Serde crates:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
Step 2: Define the Struct with Custom Serde Logic
We'll use Serde's serialize_with and deserialize_with attributes to hook into the conversion process for the my_list field. We also keep skip_serializing_if to omit the field when it's None.
use serde::{Deserialize, Serialize}; use std::collections::HashMap; pub struct MyStruct { #[serde( skip_serializing_if = "Option::is_none", serialize_with = "serialize_my_list", deserialize_with = "deserialize_my_list" )] pub my_list: Option<Vec<String>>, }
Step 3: Implement Custom Serialization
This function converts a Vec<String> back into a JSON object where each string becomes a key with an empty object as its value:
fn serialize_my_list<S>(value: &Option<Vec<String>>, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer, { match value { None => serializer.serialize_none(), Some(list) => { let mut map = serializer.serialize_map(Some(list.len()))?; for key in list { // Serialize each key with an empty object as its value map.serialize_entry(key, &serde_json::json!({}))?; } map.end() } } }
Step 4: Implement Custom Deserialization
This function reads a JSON object, validates that all values are empty objects, and collects the keys into a Vec<String>:
fn deserialize_my_list<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error> where D: serde::Deserializer<'de>, { // Handle cases where the field is missing or null let opt_map: Option<HashMap<String, serde_json::Value>> = Deserialize::deserialize(deserializer)?; match opt_map { None => Ok(None), Some(map) => { let mut list = Vec::new(); for (key, value) in map { // Validate each value is an empty object match value { serde_json::Value::Object(obj) if obj.is_empty() => list.push(key), _ => return Err(serde::de::Error::custom(format!( "Value for key '{}' must be an empty object", key ))), } } Ok(Some(list)) } } }
Step 5: Test the Implementation
Verify the round-trip conversion works as expected:
fn main() -> Result<(), Box<dyn std::error::Error>> { // Test deserialization from sample JSON let json_input = r#"{"mylist": {"foo": {}, "bar": {}}}"#; let my_struct: MyStruct = serde_json::from_str(json_input)?; assert_eq!(my_struct.my_list, Some(vec!["foo".to_string(), "bar".to_string()])); // Test serialization back to JSON let json_output = serde_json::to_string_pretty(&my_struct)?; println!("Serialized JSON:\n{}", json_output); // Ensure round-trip consistency let round_trip: MyStruct = serde_json::from_str(&json_output)?; assert_eq!(round_trip.my_list, my_struct.my_list); Ok(()) }
Key Notes:
- Validation: The deserialization step ensures all values in the JSON object are empty objects, which aligns with your original requirement. If you don't need this validation, you can simplify the code by collecting all keys directly.
- Null/Missing Fields: The
Option<Vec<String>>type handles cases where themylistfield is missing or set tonullin the JSON, andskip_serializing_ifensures these cases aren't serialized back.
内容的提问来源于stack exchange,提问作者Semaphor

