Десериализация списков ключей и значений как структуры из JSON с использованием serde?

У меня JSON такой:

{
    "fieldNames": ["MyInt", "MyFloat", "MyString"],
    "fieldValues": [5, 10.0, "hello"],
}

Я хочу десериализовать в такую ​​структуру:

#[derive(Deserialize)]
struct MyStruct {
    my_int: u64,
    my_float: f64,
    my_string: String,
}

Есть ли способ сделать это с serde? В идеале я хотел бы что-то вроде:

#[serde(keys="fieldNames", values="fieldValues")]

person spease    schedule 21.11.2017    source источник


Ответы (1)


Что-то вроде этого может сработать. Это использует функцию deserialize_with, которую можно вызвать из любой структуры, содержащей эту.


#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use serde::de::{self, Deserialize, DeserializeOwned, Deserializer};
use serde_json::Value;

#[derive(Deserialize, Debug)]
struct Spease(#[serde(deserialize_with = "names_values")] MyStruct);

#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
struct MyStruct {
    my_int: u64,
    my_float: f64,
    my_string: String,
}

fn names_values<'de, T, D>(deserializer: D) -> Result<T, D::Error>
where
    T: DeserializeOwned,
    D: Deserializer<'de>
{
    #[derive(Deserialize)]
    struct Helper {
        #[serde(rename = "fieldNames")]
        names: Vec<String>,
        #[serde(rename = "fieldValues")]
        values: Vec<Value>,
    }

    // Deserialize a Vec<String> and Vec<Value>.
    let nv = Helper::deserialize(deserializer)?;

    // Zip them together into a map.
    let pairs = Value::Object(nv.names.into_iter().zip(nv.values).collect());

    // Deserialize the output type T.
    T::deserialize(pairs).map_err(de::Error::custom)
}

fn main() {
    let j = r#"{
                 "fieldNames": ["MyInt", "MyFloat", "MyString"],
                 "fieldValues": [5, 10.0, "hello"]
               }"#;

    println!("{:?}", serde_json::from_str::<Spease>(j).unwrap());
}
person dtolnay    schedule 21.11.2017
comment
Это замечательно. Мне любопытно, почему вы решили использовать Owned/String/Value? Является ли это более эффективным или что-то, что можно оптимизировать с большей работой? (Я попытался заменить его на &str и столкнулся с ошибками, а затем отказался от изменения) - person spease; 26.11.2017