有没有一种方法可以像反序列化一样派生结构以从 serde_json::Value 获得自动转换?
Is there a way to derive a struct like with Deserialize to get automatic transform from serde_json::Value?
从字符串直接反序列化为结构非常有效。但在某些情况下,您可能已经有了一个 serde_json::Value
,并想尝试将其转换为结构。
以下示例说明了这一点:从 JSON(例如在网络库中)加载一个 Request
结构,使用类型字符串和通用内容作为值,然后您想要调用处理程序(来自客户端库)并将值转换为给定结构。
use serde::Deserialize;
use serde_json::{json, Value};
use std::convert::TryFrom;
use std::error::Error;
#[derive(Deserialize)]
struct Request {
#[serde(alias = "type")]
req_type: String,
content: Value
}
#[derive(Deserialize)]
struct Person {
name: String,
age: u8
}
// It there a way to avoid having to declare this???
impl TryFrom<Value> for Person {
type Error = serde_json::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
Person::deserialize(value)
}
}
fn say_hello(p: Person) {
println!("Hello, I'm {}, and I'm {} years old!", p.name, p.age);
}
fn main() -> Result<(), Box<dyn Error>> {
let req: Request = Request::deserialize(json!({
"type": "sayHello",
"content": {
"name": "Pierre",
"age": 32
}
}))?;
match req.req_type.as_str() {
"sayHello" => say_hello(req.content.try_into()?),
_ => println!("unknown request")
}
Ok(())
}
所以问题是:是否实施了一些 derive
或其他魔术,允许与 String 中的 Deserialize
相同的行为,以便客户端只能写:
#[derive(Deserialize)]
struct Person {
name: String,
age: u8
}
fn say_hello(p: Person) {
println!("Hello, I'm {}, and I'm {} years old!", p.name, p.age);
}
我尝试了 #[serde(try_from = "Value")]
属性,但它看起来不像是为此目的而设计的...
有serde_json::from_value()
专门针对这个:
pub fn from_value<T>(value: Value) -> Result<T, Error>
where
T: DeserializeOwned,
给定任何 serde_json::Value
和一些 T: DeserializedOwned
,如果可能,该函数会将 Value
反序列化为那个 T
。
从字符串直接反序列化为结构非常有效。但在某些情况下,您可能已经有了一个 serde_json::Value
,并想尝试将其转换为结构。
以下示例说明了这一点:从 JSON(例如在网络库中)加载一个 Request
结构,使用类型字符串和通用内容作为值,然后您想要调用处理程序(来自客户端库)并将值转换为给定结构。
use serde::Deserialize;
use serde_json::{json, Value};
use std::convert::TryFrom;
use std::error::Error;
#[derive(Deserialize)]
struct Request {
#[serde(alias = "type")]
req_type: String,
content: Value
}
#[derive(Deserialize)]
struct Person {
name: String,
age: u8
}
// It there a way to avoid having to declare this???
impl TryFrom<Value> for Person {
type Error = serde_json::Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
Person::deserialize(value)
}
}
fn say_hello(p: Person) {
println!("Hello, I'm {}, and I'm {} years old!", p.name, p.age);
}
fn main() -> Result<(), Box<dyn Error>> {
let req: Request = Request::deserialize(json!({
"type": "sayHello",
"content": {
"name": "Pierre",
"age": 32
}
}))?;
match req.req_type.as_str() {
"sayHello" => say_hello(req.content.try_into()?),
_ => println!("unknown request")
}
Ok(())
}
所以问题是:是否实施了一些 derive
或其他魔术,允许与 String 中的 Deserialize
相同的行为,以便客户端只能写:
#[derive(Deserialize)]
struct Person {
name: String,
age: u8
}
fn say_hello(p: Person) {
println!("Hello, I'm {}, and I'm {} years old!", p.name, p.age);
}
我尝试了 #[serde(try_from = "Value")]
属性,但它看起来不像是为此目的而设计的...
有serde_json::from_value()
专门针对这个:
pub fn from_value<T>(value: Value) -> Result<T, Error>
where
T: DeserializeOwned,
给定任何 serde_json::Value
和一些 T: DeserializedOwned
,如果可能,该函数会将 Value
反序列化为那个 T
。