rust serde 多态问题简单说明

日常序列化是一个比较常见的问题,以下说明下一些方法

通过type 定义使用enum

  • 类型定义
pub mod app {
    use serde::{Deserialize, Serialize};
    #[derive(Debug, Serialize, Deserialize)]
    #[serde(tag = "type")]
    #[serde(rename="AnimalType")]
    pub enum Animal {
        #[serde(rename = "cat")]
        Cat { name: String, lives: u8 },
        #[serde(rename = "dog")]
        Dog { name: String, barks: bool },
    }
}
  • 使用
use json_app::app::Animal;
fn main() {
    let items: Vec<Animal> = vec![Animal::Cat { name: "Whiskers".to_string(), lives: 9 },
                                   Animal::Dog { name: "Fido".to_string(), barks: true }];
    // Serialize the items to JSON
    let data = serde_json::to_string(&items).unwrap();
    println!("{}", data);
    let animals: Vec<Animal> = serde_json::from_str(&data).unwrap();
    for animal in animals {
        match animal {
            Animal::Cat { name, lives } => {
                println!("Cat: {}, Lives: {}", name, lives);
            }
            Animal::Dog { name, barks } => {
                println!("Dog: {}, Barks: {}", name, barks);
            }
        }
    }
}

通过typetag 使用trait object

use serde::{Deserialize, Serialize};

#[typetag::serde(tag = "type")]
trait WebEvent {
    fn inspect(&self);
}

#[derive(Serialize, Deserialize)]
struct PageLoad;

#[typetag::serde]
impl WebEvent for PageLoad {
    fn inspect(&self) {
        println!("200 milliseconds or bust");
    }
}

#[derive(Serialize, Deserialize)]
struct Click {
    x: i32,
    y: i32,
}

#[typetag::serde]
impl WebEvent for Click {
    fn inspect(&self) {
        println!("negative space between the ads: x={} y={}", self.x, self.y);
    }
}

pub fn send_event_to_money_factory() -> serde_json::Result<()> {
    let page_load = PageLoad;
    let event = &page_load as &dyn WebEvent;
    let json = serde_json::to_string(event)?;
    println!("PageLoad json: {}", json);
    let de: Box<dyn WebEvent> = serde_json::from_str(&json)?;
    de.inspect();

    println!();

    let click = Click { x: 10, y: 10 };
    let event = &click as &dyn WebEvent;
    let json = serde_json::to_string(event)?;
    println!("Click json: {}", json);
    let de: Box<dyn WebEvent> = serde_json::from_str(&json)?;
    de.inspect();

    Ok(())
}

说明

rust 的trait object 是一个比较强大的特性,使用好可以解决不少问题,实际上trait object 的玩法与tag type 模式是类似的,就是灵活性更好

参考资料

https://github.com/serde-rs/serde

https://serde.rs/examples.html

https://github.com/dtolnay/typetag

posted on 2025-09-02 08:00  荣锋亮  阅读(17)  评论(0)    收藏  举报

导航