【问题标题】:How do I create a generic struct that can be serialized with Serde and retain type information?如何创建可以使用 Serde 序列化并保留类型信息的通用结构?
【发布时间】:2018-03-29 09:47:00
【问题描述】:

我想使用 Serde 序列化一个通用的数据结构。

我的库的用户应该能够提供他们自己的实现SerializeDeserialize 的结构。我应该能够取回他们序列化数据所用值的原始类型信息。

我该怎么做呢?

我尝试过这样的事情:

#[derive(Serialize, Deserialize)]
struct Message<V> {
    key: Key,
    value: V,
}

我想在反序列化数据后取回V的类型。

这是这样做的方式还是我偏离了轨道?

我希望用户能够扩展可能的值/类型。我想要枚举的行为,但用户可以灵活地添加自己的结构作为可能的候选者。类似于this code,但它们都需要唯一的ids

【问题讨论】:

标签: generics serialization rust traits serde


【解决方案1】:

我很确定这在一般意义上是完全不可能的。

每种类型都能够控制自己的序列化。这意味着多种类型最终可能会序列化为相同的值

#[derive(Debug, Deserialize, Serialize)]
struct Age(i32);

#[derive(Debug, Deserialize, Serialize)]
struct Weight(i32);

fn main() {
    let a = Age(42);
    let a_str = serde_json::to_string(&a).unwrap();
    println!("{}", a_str); // 42
    let b: Weight = serde_json::from_str(&a_str).unwrap();
    println!("{:?}", b);
}

您可以尝试在序列化数据中建立标识类型的标记,但最终会出现相同的问题:总是存在冲突的可能性。

更根本的是,这样的概念在 Rust 中是无效的,因为每种类型在编译时都必须有一个已知的大小。无法反序列化为未知大小的变量。

同样从根本上说,您将为通用 V 提供什么类型?编译代码时不能“忘记”指定所有泛型类型。

因此,通常这种事情甚至不会出现。如果用户使用具体类型调用您的序列化代码,他们可以使用相同的具体类型调用您的反序列化代码。

我想要枚举的行为,但用户可以灵活地添加自己的结构。

这听起来像一个特征对象

另见:

【讨论】:

    【解决方案2】:

    实现这种想法的最佳方法是限制 V 的类型,然后使用结构名称作为识别模块的类型+字符串的方法。

    例子

    pub struct Message<V: Serialize + Deserialize> {
         key: keytype,
         value: V,
         crate_path: String
    }
    

    然后使用 sha 之类的东西为结构名称生成哈希,反序列化以检查结构名称。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多