简体   繁体   English

rust:使用 serde_json 向现有结构添加字段

[英]rust: adding a field to an existing struct with serde_json

I have a pre-defined struct我有一个预定义的结构

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]}

}

How can I put both struct under Foo or is it possible to first serialize Bar to json and add Bar2 as string literals?如何将两个结构都放在Foo下,或者是否可以先将Bar序列化为 json 并将Bar2添加为字符串文字? The result would be a json结果将是一个json

{"foo": [{"a": "something"}, {"a": "something2"}], "b": "something"}

You can get this serialized structure by storing both Foo and Bar2 in another struct and merge them together with #[serde(flatten)] .您可以通过将FooBar2存储在另一个结构中并将它们与#[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"}

If instead by "no modification of struct" you meant by only serializing Foo and just modifying T , then no its not possible to get that output with serde directly.如果改为“不修改结构” ,您的意思是仅序列化Foo并仅修改T ,那么不可能直接使用serde获得该输出。 You'd have to do your proposed method by serializing into Value s and merging them yourself.您必须通过序列化为Value并自己合并它们来执行您提出的方法。

I see two problems with your code:我发现您的代码有两个问题:

  • You haven't derived Serialize for Bar and Bar2 .您还没有为BarBar2派生Serialize
  • You're trying to put a_vec and b_vec into a vector, which you can't do because they're of different type.您试图将a_vecb_vec放入一个向量中,但您不能这样做,因为它们的类型不同。

The latter problem can be solved by dynamic dispatch.后一个问题可以通过动态调度来解决。 Instead of putting a_vec into the Vec , you put &a_vec as &dyn Serialize , ie just give it a reference to some serializable object.不是将a_vec放入Vec ,而是将&a_vec as &dyn Serialize ,即只给它一个对某些可序列化对象的引用。 Slight trouble is that this won't work with serde::Serialize because it's not object safe.小麻烦是这不适用于serde::Serialize因为它不是对象安全的。 This is what erased_serde is for:这就是erased_serde的用途:

let foo = Foo::<Vec<&dyn erased_serde::Serialize>> {
    foo: vec![&a_vec, &b_vec],
};
println!("{}", serde_json::to_string_pretty(&foo).unwrap());

will work fine.会正常工作。 But it will output但它会输出

{"foo":[[{"a":"something"},{"a":"something2"}],[{"b":"something"}]]}

which is not what you wanted?这不是你想要的?

To get the output you wanted, ie serialize Foo and add a field to it, you could use #[serde(flatten)] :要获得您想要的输出,即序列化 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());

The output of serializing Merge both the fields from T1 and T2 .序列化的输出Merge来自T1T2的两个字段。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM