Как десериализовать в Rust (используя serde) необязательный параметр json, который может быть строковым или строковым массивом - PullRequest
0 голосов
/ 27 мая 2020

Я новичок в Rust и пытаюсь десериализовать данные JSON с помощью библиотеки serde. У меня следующая структура JSON:

{
    “foo”: “bar”,
    “speech”: “something”
}

или

{
    “foo”: “bar”,
    “speech”: [“something”, “something else”]
}

или

{
    “foo”: “bar”,
}

Т.е. речь не является обязательной и может быть строкой или массивом строк.

Я могу обрабатывать десериализацию строки / массива строк, используя следующий подход:

#[derive(Debug, Serialize, Deserialize)]
   struct foo {
   pub foo: String,
   #[serde(deserialize_with = "deserialize_message_speech")]
   speech: Vec<String>
}

Я также могу обрабатывать десериализацию необязательного атрибута строки / массива строк, используя подход:

#[derive(Debug, Serialize, Deserialize)]
struct foo {
   pub foo: String,
   #[serde(skip_serializing_if = "Option::is_none")]
   speech: Option<Vec<String>>
}

или

struct foo {
   pub foo: String,
   #[serde(skip_serializing_if = "Option::is_none")]
   speech: Option<String>
}

Но объединить все вместе просто не получится. Кажется, что deserialize_with не работает должным образом с типом Option . Может ли кто-нибудь посоветовать самый простой и тривиальный способ реализовать это (serde может быть довольно сложным, я видел некоторые сумасшедшие вещи :))?

Ответы [ 2 ]

3 голосов
/ 27 мая 2020

Попробуйте использовать тип Enum для поля speech:

#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum Speech {
    Str(String),
    StrArray(Vec<String>),   
}

#[derive(Debug, Serialize, Deserialize)]
   struct foo {
   pub foo: String,
   speech: Option<Speech>,
}

Enum - это go способ представления вариантного типа в Rust. Подробнее см. https://serde.rs/enum-representations.html.

0 голосов
/ 27 мая 2020

с # [serde (без тегов)] работает!

use serde_json;
use std::result::Result;
use std::error::Error;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Speech {
    Str(String),
    StrArray(Vec<String>),   
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
   pub foo: String,
   #[serde(skip_serializing_if = "Option::is_none")]
   speech: Option<Speech>,
} 

fn main() -> Result<(), Box<dyn Error>> {

    let json1 = r#"
    {
        "foo": "bar",
        "speech": "something"
    }
    "#;    

    let json2 = r#"
    {
        "foo": "bar",
        "speech": ["something", "something else"]
    }
    "#;    


    let json3 = r#"
    {
        "foo": "bar"
    }
    "#;    

    let foo1: Foo = serde_json::from_str(json1)?;
    let back_to_str_foo1 = serde_json::to_string(&foo1).unwrap();
    println!("foo1 {:#?}", foo1);
    println!("back_to_str_foo1 {}", back_to_str_foo1);

    let foo2: Foo = serde_json::from_str(json2)?;
    let back_to_str_foo2 = serde_json::to_string(&foo2).unwrap();
    println!("foo1 {:#?}", foo2);
    println!("back_to_str_foo2 {}", back_to_str_foo2);


    let foo3: Foo = serde_json::from_str(json3)?;
    let back_to_str_foo3 = serde_json::to_string(&foo3).unwrap();
    println!("foo1 {:#?}", foo3);
    println!("back_to_str_foo3 {}", back_to_str_foo3);

    Ok(())
}
...