rust:使用 serde_json 向现有结构添加字段
rust: adding a field to an existing struct with serde_json
我有一个预定义的结构
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Foo<T>
where T: Serialize
{
foo: T
}
struct Bar{
a: String
}
struct Bar2{
b: String
}
fn main() -> Result<()>
{
let a1 = Bar {a: "something".to_owned(),};
let a2 = Bar {a: "something2".to_owned(),};
let a_vec: Vec<Bar> = vec![a1, a2];
let b = Bar2 {b: "something"}
let b_vec: Vec<Bar2> = vec![b];
//let foo = Foo {foo: vec![a_vec,b_vec]}
}
如何将两个结构都放在 Foo
下,或者是否可以先将 Bar
序列化为 json 并添加 Bar2
作为字符串文字?结果将是 json
{"foo": [{"a": "something"}, {"a": "something2"}], "b": "something"}
您可以通过将 Foo
和 Bar2
存储在另一个结构中并将它们 合并 与 #[serde(flatten)]
一起获得此序列化结构。 (playground):
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Foo<T>
where
T: Serialize,
{
foo: T,
}
#[derive(Debug, Serialize)]
struct Bar {
a: String,
}
#[derive(Debug, Serialize)]
struct Bar2 {
b: String,
}
#[derive(Debug, Serialize)]
struct Outer<T: Serialize> {
#[serde(flatten)]
field_1: Foo<T>,
#[serde(flatten)]
field_2: Bar2,
}
fn main() {
let a1 = Bar {
a: "something".to_owned(),
};
let a2 = Bar {
a: "something2".to_owned(),
};
let a_vec: Vec<Bar> = vec![a1, a2];
let b = Bar2 {
b: "something".to_owned(),
};
let o = Outer {
field_1: Foo { foo: a_vec },
field_2: b,
};
println!("{}", serde_json::to_string(&o).unwrap());
}
{"foo":[{"a":"something"},{"a":"something2"}],"b":"something"}
如果改为 “不修改结构” 你的意思是只序列化 Foo
并且只修改 T
,那么不可能得到直接用 serde
输出。您必须通过序列化为 Value
s 并自己合并它们来执行您建议的方法。
我发现您的代码有两个问题:
- 您还没有为
Bar
和 Bar2
导出 Serialize
。
- 您正在尝试将
a_vec
和 b_vec
放入向量中,但您不能这样做,因为它们属于不同的类型。
后一个问题可以通过动态调度来解决。不是将 a_vec
放入 Vec
,而是放入 &a_vec as &dyn Serialize
,即只给它一个对某个可序列化对象的引用。有点麻烦的是这不适用于 serde::Serialize
因为它不是对象安全的。这就是 erased_serde
的用途:
let foo = Foo::<Vec<&dyn erased_serde::Serialize>> {
foo: vec![&a_vec, &b_vec],
};
println!("{}", serde_json::to_string_pretty(&foo).unwrap());
会很好用。但是会输出
{"foo":[[{"a":"something"},{"a":"something2"}],[{"b":"something"}]]}
哪一个不是你想要的?
要获得您想要的输出,即序列化 Foo 并向其添加一个字段,您可以使用 #[serde(flatten)]
:
let foo = Foo { foo: a_vec };
#[derive(Serialize)]
struct Merge<T1: Serialize, T2: Serialize> {
#[serde(flatten)]
f1: T1,
#[serde(flatten)]
f2: T2,
}
let out = Merge { f1: &foo, f2: &b };
println!("{}", serde_json::to_string_pretty(&out).unwrap());
序列化 Merge
来自 T1
和 T2
的字段的输出。
我有一个预定义的结构
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Foo<T>
where T: Serialize
{
foo: T
}
struct Bar{
a: String
}
struct Bar2{
b: String
}
fn main() -> Result<()>
{
let a1 = Bar {a: "something".to_owned(),};
let a2 = Bar {a: "something2".to_owned(),};
let a_vec: Vec<Bar> = vec![a1, a2];
let b = Bar2 {b: "something"}
let b_vec: Vec<Bar2> = vec![b];
//let foo = Foo {foo: vec![a_vec,b_vec]}
}
如何将两个结构都放在 Foo
下,或者是否可以先将 Bar
序列化为 json 并添加 Bar2
作为字符串文字?结果将是 json
{"foo": [{"a": "something"}, {"a": "something2"}], "b": "something"}
您可以通过将 Foo
和 Bar2
存储在另一个结构中并将它们 合并 与 #[serde(flatten)]
一起获得此序列化结构。 (playground):
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct Foo<T>
where
T: Serialize,
{
foo: T,
}
#[derive(Debug, Serialize)]
struct Bar {
a: String,
}
#[derive(Debug, Serialize)]
struct Bar2 {
b: String,
}
#[derive(Debug, Serialize)]
struct Outer<T: Serialize> {
#[serde(flatten)]
field_1: Foo<T>,
#[serde(flatten)]
field_2: Bar2,
}
fn main() {
let a1 = Bar {
a: "something".to_owned(),
};
let a2 = Bar {
a: "something2".to_owned(),
};
let a_vec: Vec<Bar> = vec![a1, a2];
let b = Bar2 {
b: "something".to_owned(),
};
let o = Outer {
field_1: Foo { foo: a_vec },
field_2: b,
};
println!("{}", serde_json::to_string(&o).unwrap());
}
{"foo":[{"a":"something"},{"a":"something2"}],"b":"something"}
如果改为 “不修改结构” 你的意思是只序列化 Foo
并且只修改 T
,那么不可能得到直接用 serde
输出。您必须通过序列化为 Value
s 并自己合并它们来执行您建议的方法。
我发现您的代码有两个问题:
- 您还没有为
Bar
和Bar2
导出Serialize
。 - 您正在尝试将
a_vec
和b_vec
放入向量中,但您不能这样做,因为它们属于不同的类型。
后一个问题可以通过动态调度来解决。不是将 a_vec
放入 Vec
,而是放入 &a_vec as &dyn Serialize
,即只给它一个对某个可序列化对象的引用。有点麻烦的是这不适用于 serde::Serialize
因为它不是对象安全的。这就是 erased_serde
的用途:
let foo = Foo::<Vec<&dyn erased_serde::Serialize>> {
foo: vec![&a_vec, &b_vec],
};
println!("{}", serde_json::to_string_pretty(&foo).unwrap());
会很好用。但是会输出
{"foo":[[{"a":"something"},{"a":"something2"}],[{"b":"something"}]]}
哪一个不是你想要的?
要获得您想要的输出,即序列化 Foo 并向其添加一个字段,您可以使用 #[serde(flatten)]
:
let foo = Foo { foo: a_vec };
#[derive(Serialize)]
struct Merge<T1: Serialize, T2: Serialize> {
#[serde(flatten)]
f1: T1,
#[serde(flatten)]
f2: T2,
}
let out = Merge { f1: &foo, f2: &b };
println!("{}", serde_json::to_string_pretty(&out).unwrap());
序列化 Merge
来自 T1
和 T2
的字段的输出。