首页 > 解决方案 > 将 serde 与 trait 对象一起使用

问题描述

我正在尝试使用 serde 序列化特征对象。我看了看

但我不明白如何把这些碎片放在一起。请告诉我如何进行此操作。


这段代码模仿了Rust 编程语言中的示例:

use serde::Serialize; // 1.0.126

trait Paint: Serialize {
    fn paint(&self) -> String;
}

#[derive(Serialize)]
struct Pen {
    color: String,
}

#[derive(Serialize)]
struct Brush {
    color: String,
}

impl Paint for Pen {
    fn paint(&self) -> String {
        return format!("Pen painting with color {}", self.color);
    }
}

impl Paint for Brush {
    fn paint(&self) -> String {
        return format!("Brush painting with color {}", self.color);
    }
}

#[derive(Serialize)]
struct Canvas {
    height: f32,
    width: f32,
    tools: Vec<Box<dyn Paint>>,
}

impl Paint for Canvas {
    fn paint(&self) -> String {
        let mut s = String::new();
        for tool in &self.tools {
            s.push_str("\n");
            s.push_str(&tool.paint());
        }

        return s;
    }
}

fn main() {
    let pen = Pen {
        color: "red".to_owned(),
    };
    let brush = Brush {
        color: "blue".to_owned(),
    };
    let canvas = Canvas {
        height: 12.0,
        width: 10.0,
        tools: vec![Box::new(pen), Box::new(brush)],
    };

    println!("{}", canvas.paint());
    serde_json::to_string(&canvas).unwrap();
}

由于对象安全规则,代码无法编译:

error[E0038]: the trait `Paint` cannot be made into an object
   --> src/main.rs:33:12
    |
33  |     tools: Vec<Box<dyn Paint>>,
    |            ^^^^^^^^^^^^^^^^^^^ `Paint` cannot be made into an object
    |
    = help: consider moving `serialize` to another trait
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.126/src/ser/mod.rs:247:8
    |
247 |     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    |        ^^^^^^^^^ ...because method `serialize` has generic type parameters
    | 
   ::: src/main.rs:3:7
    |
3   | trait Paint: Serialize {
    |       ----- this trait cannot be made into an object...

我知道特征对象不能具有带有泛型参数的方法,但在我的情况下,我只需要将Canvas结构序列化为 JSON。有什么我可以做的吗?

理想的序列化输出将是

{
    "Canvas": {
        "height": 12.0,
        "width": 10.0,
        "tools": {
            "Pen": {
                "color": "red"
            },
            "Brush": {
                "color": "blue"
            }
        }
    }
}

标签: rustserde

解决方案


推荐阅读