如何为盒装特征对象实现`serde :: Serialize`?

sno*_*ane 7 polymorphism rust serde

我试图为结构创建一个通用向量时遇到了问题.这是我的第一次尝试:

#[derive(Serialize)]
struct Card {
    sections: Vec<Section<WidgetTrait>>
}

#[derive(Serialize)]
struct Section<T: WidgetTrait> {
    header: String,
    widgets: Vec<T>
}
Run Code Online (Sandbox Code Playgroud)

这使我遇到了一个Sized未实现的错误,并且WidgetTrait在编译时未知大小.

我的下一次尝试是这样使用Box<WidgetTrait>:

#[derive(Serialize)]
struct Section {
    header: String,
    widgets: Vec<Box<WidgetTrait>>
}
Run Code Online (Sandbox Code Playgroud)

操场

这导致了一个错误:

error[E0277]: the trait bound `WidgetTrait: serde::Serialize` is not satisfied
  --> src/main.rs:11:10
   |
11 | #[derive(Serialize)]
   |          ^^^^^^^^^ the trait `serde::Serialize` is not implemented for `WidgetTrait`
   |
   = note: required because of the requirements on the impl of `serde::Serialize` for `std::boxed::Box<WidgetTrait>`
   = note: required because of the requirements on the impl of `serde::Serialize` for `std::vec::Vec<std::boxed::Box<WidgetTrait>>`
   = note: required by `serde::ser::SerializeStruct::serialize_field`
Run Code Online (Sandbox Code Playgroud)

我的目标是使Sectionstruct中的小部件向量能够接受实现WidgetTrait特征的不同类型的小部件,就像使用接口一样.

dto*_*nay 5

要序列化Serde trait对象,您应该使用erased-serde.

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate erased_serde;

extern crate serde;
extern crate serde_json;

#[derive(Serialize)]
struct Card {
    sections: Vec<Section>,
}

#[derive(Serialize)]
struct Section {
    header: String,
    widgets: Vec<Box<WidgetTrait>>,
}

#[derive(Serialize)]
struct Image {
    image_url: String,
}

#[derive(Serialize)]
struct KeyValue {
    top_label: String,
    content: String,
}

trait WidgetTrait: erased_serde::Serialize {}
impl WidgetTrait for Image {}
impl WidgetTrait for KeyValue {}

serialize_trait_object!(WidgetTrait);

fn main() {
    let card = Card {
        sections: vec![
            Section {
                header: "text".to_owned(),
                widgets: vec![
                    Box::new(Image {
                        image_url: "img".to_owned(),
                    }),
                    Box::new(KeyValue {
                        top_label: "text".to_owned(),
                        content: "text".to_owned(),
                    }),
                ],
            },
        ],
    };

    println!("{}", serde_json::to_string_pretty(&card).unwrap());
}
Run Code Online (Sandbox Code Playgroud)