serialization - 我如何反序列化为特征,而不是具体类型?

标签 serialization rust serde cbor

我正在尝试进行结构序列化,在这种序列化中,字节最终将沿着管道发送、重构并调用它们的方法。

我创建了一个特征,这些结构将适本地实现,并且我使用 serde 和 serde-cbor 进行序列化:

extern crate serde_cbor;
#[macro_use]
extern crate serde_derive;
extern crate serde;

use serde_cbor::ser::*;
use serde_cbor::de::*;

trait Contract {
    fn do_something(&self);
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
    x: u32,
    y: u32,
}

#[derive(Debug, Serialize, Deserialize)]
struct Bar {
    data: Vec<Foo>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Baz {
    data: Vec<Foo>,
    tag: String,
}

impl Contract for Bar {
    fn do_something(&self) {
        println!("I'm a Bar and this is my data {:?}", self.data);
    }
}

impl Contract for Baz {
    fn do_something(&self) {
        println!("I'm Baz {} and this is my data {:?}", self.tag, self.data);
    }
}

fn main() {
    let data = Bar { data: vec![Foo { x: 1, y: 2 }, Foo { x: 3, y: 4 }, Foo { x: 7, y: 8 }] };
    data.do_something();

    let value = to_vec(&data).unwrap();
    let res: Result<Contract, _> = from_reader(&value[..]);
    let res = res.unwrap();
    println!("{:?}", res);
    res.do_something();
}

当我尝试使用特征作为类型重建字节时(假设我不知道正在发送哪个底层对象),编译器提示特征没有实现 Sized特点:

error[E0277]: the trait bound `Contract: std::marker::Sized` is not satisfied
  --> src/main.rs:52:15
   |
52 |     let res: Result<Contract, _> = from_reader(&value[..]);
   |              ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `Contract`
   |
   = note: `Contract` does not have a constant size known at compile-time
   = note: required by `std::result::Result`

我想这是有道理的,因为编译器不知道结构应该有多大,也不知道如何为它排列字节。如果我更改反序列化对象的行以指定实际的结构类型,它会起作用:

let res: Result<Bar, _> = from_reader(&value[..]);

是否有更好的模式来实现这种序列化+多态行为?

最佳答案

看起来你掉进了我从 C++ 迁移到 Rust 时掉入的同一个陷阱。尝试使用多态性来模拟一组固定的类型变体。 Rust 的枚举(类似于 Haskell 的枚举,相当于 Ada 的变体记录类型)不同于其他语言中的经典枚举,因为枚举变体可以有自己的字段。

我建议您将代码更改为

#[derive(Debug, Serialize, Deserialize)]
enum Contract {
    Bar { data: Vec<Foo> },
    Baz { data: Vec<Foo>, tag: String },
}

#[derive(Debug, Serialize, Deserialize)]
struct Foo {
    x: u32,
    y: u32,
}

impl Contract {
    fn do_something(&self) {
        match *self {
            Contract::Bar { ref data } => println!("I'm a Bar and this is my data {:?}", data),
            Contract::Baz { ref data, ref tag } => {
                println!("I'm Baz {} and this is my data {:?}", tag, data)
            }
        }
    }
}

关于serialization - 我如何反序列化为特征,而不是具体类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53996911/

相关文章:

Java 通用可序列化、可迭代堆栈

rust - 使用新的异步/等待语法发送多组 HTTP 请求并控制工作人员数量的最快方法

rust - 在 Rust 中实现通用的可递增特征

rust - 如何使用 Serde 在序列化期间转换字段?

json - 从 serde_json 中的非类型化 JSON 中提取数据时如何处理错误?

android - 序列化 Android View - 从 IllegalAccessException 导致 InvalidClassException

c# - 如何在wcf中序列化 protected 属性

vector - 带向量的Rust匹配可变枚举引用

rust - 如何解析包含简单列表和键值列表(关联数组)的YAML

c# - 如何在 JsonConverter 的 Json.net 中设置只读属性值