如何在 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(())
}
我是 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(())
}