如何在 Rust 中反序列化(使用 serde)可选 json 参数,可以是字符串或字符串数​​组

How to deserialize in Rust (using serde) optional json parameter that can be either string or string array

我是 Rust 的新手,我正在尝试使用 serde 库反序列化 JSON 数据。 我有以下 JSON 结构:

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

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

{
    “foo”: “bar”,
}

speech 是可选的,它可以是字符串或字符串数​​组。

我可以使用以下方法处理字符串的反序列化 string/array:

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

我还可以使用以下方法处理反序列化可选 string/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 可能非常复杂,我看到了一些疯狂的东西:))?

尝试为 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>,
}

枚举是在 Rust 中表示变体类型的首选方法。有关详细信息,请参阅 https://serde.rs/enum-representations.html

使用 #[serde(untagged)] 有效!

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(())
}