Rust中更优反序列化嵌套JSON对象的方案咨询
寻求更优的嵌套JSON反序列化方案
待反序列化的JSON对象:
{"name":"John Doe","age":43,"address":"{\"street\":\"10 Downing Street\",\"city\":\"London\"}"}
我目前用以下Rust代码实现了功能:
use serde_derive::{Deserialize, Serialize}; use serde_json::{Result, Value}; #[derive(Serialize, Deserialize)] struct Person{ name: String, address: Value } #[derive(Debug, Serialize, Deserialize)] struct Address{ street: String, city: String } impl From<Person> for Address{ fn from(p: Person) -> Self { let str_val: String = serde_json::from_value(p.address).unwrap(); let ad: Self = serde_json::from_str(&str_val).unwrap(); ad } } fn main() -> Result<()> { let data = r#"{"name":"John Doe","age":43,"address":"{\"street\":\"10 Downing Street\",\"city\":\"London\"}"}"#; let p: Person = serde_json::from_str(data).unwrap(); println!("{:?}", Address::from(p)); Ok(()) }
但我觉得应该有更优的实现方式,请问有哪些改进建议?
改进建议
1. 自定义反序列化逻辑,一步完成转换
不需要先转成Value再二次解析,可以直接为Person结构体的address字段实现自定义反序列化,把字符串形式的JSON直接解析成Address类型,减少中间步骤,代码更简洁:
use serde::{Deserialize, Deserializer}; use serde_derive::{Deserialize, Serialize}; use serde_json::Result; #[derive(Debug, Serialize, Deserialize)] struct Person { name: String, age: u32, #[serde(deserialize_with = "deserialize_address")] address: Address, } #[derive(Debug, Serialize, Deserialize)] struct Address { street: String, city: String, } // 自定义反序列化函数:把字符串转成Address fn deserialize_address<'de, D>(deserializer: D) -> Result<Address, D::Error> where D: Deserializer<'de>, { let address_str: String = String::deserialize(deserializer)?; serde_json::from_str(&address_str).map_err(serde::de::Error::custom) } fn main() -> Result<()> { let data = r#"{"name":"John Doe","age":43,"address":"{\"street\":\"10 Downing Street\",\"city\":\"London\"}"}"#; let p: Person = serde_json::from_str(data)?; println!("{:?}", p.address); Ok(()) }
2. 避免使用unwrap(),优雅处理错误
原代码多次用unwrap(),一旦JSON格式错误会直接panic。改用?操作符传递错误,结合map_err转换错误类型,让程序能优雅处理解析失败的情况,符合Rust错误处理规范。
3. 合并不必要的结构体转换
如果只需要提取Address,可以直接通过临时结构体先取出address字段的字符串,再解析成Address,省去From转换的步骤:
use serde_json::Result; use serde_derive::Deserialize; #[derive(Debug, Deserialize)] struct Address { street: String, city: String, } fn main() -> Result<()> { let data = r#"{"name":"John Doe","age":43,"address":"{\"street\":\"10 Downing Street\",\"city\":\"London\"}"}"#; // 临时结构体仅用于提取address字符串 #[derive(Deserialize)] struct Temp { address: String } let temp: Temp = serde_json::from_str(data)?; let address: Address = serde_json::from_str(&temp.address)?; println!("{:?}", address); Ok(()) }
4. 补全字段,避免数据丢失
原代码的Person结构体未定义age字段,解析时会自动忽略这个字段,建议补上该字段,避免意外丢失JSON中的数据。
内容的提问来源于stack exchange,提问作者miimote
相关产品推荐
相关产品推荐

