Как преобразовать поле в строку с помощью Serde?

У меня есть настраиваемое поле в моем JSON, которое становится динамическим и должно быть проанализировано для структуры, которая имеет поле HashMap, подобное следующему:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

use std::collections::HashMap;

#[derive(Serialize, Deserialize)]
struct MyStruct {
    field1: String,
    custom: HashMap<String, String>,
}

fn main() {
    let json_string = r#"{"field1":"3","custom":{"custom1":"15000","custom2":"60"}}"#;
    let my_struct = serde_json::from_str::<MyStruct>(json_string).unwrap();
    println!("{}", serde_json::to_string(&my_struct).unwrap());
}

Он работает, когда моя строка json имеет строковые поля в настраиваемом поле, которые можно легко проанализировать в строку.

Но проблема в том, что моя строка json:

let json_string_wrong = r#"{"field1":"3","custom":{"custom1":15000,"custom2":"60"}}"#; // Need to parse this

Как обрабатывать такие отливки в серде?


person Akiner Alkan    schedule 22.01.2019    source источник


Ответы (1)


Serde предоставляет serde_json::Value (справочник). Это перечисление, которое содержит такие типы данных, как:

pub enum Value {
    /// Represents a JSON null value.
    Null,
    /// Represents a JSON boolean.
    Bool(bool),

    /// Represents a JSON number, whether integer or floating point.
    Number(Number),

    /// Represents a JSON string.
    String(String),

    /// Represents a JSON array.
    Array(Vec<Value>),

    /// Represents a JSON object.
    Object(Map<String, Value>),
}

Вы можете использовать serde_json::Value как тип значения для вашего HashMap. Просто можно получить данные из serde_json::Value с помощью serde_json :: from_value или используйте сопоставление с образцом. В вашем случае я бы использовал сопоставление с образцом, потому что только Integer типы будут преобразованы в String, а остальные будут такими же.

Но вам нужно подумать о добавлении еще одного шага после десериализации. Нравиться

  • Создание теневого поля для custom, будет заполнено после десериализации.
  • Или создание новой структуры, которая содержит custom как HashMap<String, String>.
  • Добавьте функцию для преобразования HashMap<String, Value> в HashMap<String, String>,

Реализация этой черты может решить вашу проблему.

trait ToStringStringMap {
    fn to_string_string_map(&self) -> HashMap<String, String>;
}

impl ToStringStringMap for HashMap<String, Value> {
    fn to_string_string_map(&self) -> HashMap<String, String> {
        self.iter()
            .map(|(k, v)| {
                let v = match v.clone() {
                    e @ Value::Number(_) | e @ Value::Bool(_) => e.to_string(),
                    Value::String(s) => s,
                    _ => {
                        println!(r#"Warning : Can not convert field : "{}'s value to String, It will be empty string."#, k);
                        "".to_string()
                    }
                };

                (k.clone(), v)
            })
            .collect()
    }
}

Пример: Детская площадка

Примечание. Название черты выбрано неудачно, предложения приветствуются.

person Ömer Erden    schedule 23.01.2019