17

我正在尝试解决序列化和反序列化的问题Box<SomeTrait>。我知道在封闭类型层次结构的情况下,推荐的方法是使用枚举并且它们的序列化没有问题,但在我的情况下使用枚举是一个不合适的解决方案。

起初我尝试使用 Serde,因为它是事实上的 Rust 序列化机制。Serde 能够序列化Box<X>,但不能在 whenX是一个特征的情况下。Serialize不能为 trait 对象实现 trait,因为它具有泛型方法。这个特殊问题可以通过使用擦除的serde来解决,这样序列化就Box<SomeTrait>可以工作了。

主要问题是反序列化。要反序列化多态类型,您需要在序列化数据中有一些类型标记。此标记应首先反序列化,然后用于动态获取将返回的函数Box<SomeTrait>

std::any::TypeId可以用作标记类型,但主要问题是如何动态获取反序列化函数。我不考虑为每个应在应用程序初始化期间手动调用的多态类型注册一个函数的选项。

我知道两种可能的方法:

  1. 像 C# 这样具有运行时反射的语言可以使用它来获取反序列化方法。
  2. 在 C++ 中,谷物库使用静态对象的魔法在库初始化时将反序列化器注册到静态映射中。

但是这些选项在 Rust 中都不可用。如果有的话,如何在 Rust 中添加多态对象的反序列化?

4

3 回答 3

9

这已由dtolnay 实施

这个概念非常聪明,解释如下README

它是如何工作的?

我们使用inventorycrate 生成您的 trait 的 impls 注册表,该注册表建立在ctorcrate 之上,用于连接插入注册表的初始化函数。第一个Box<dyn Trait>反序列化将执行迭代注册表和构建标签映射到反序列化函数的工作。随后的反序列化在该映射中找到正确的反序列化函数。板条箱也参与其中erased-serde,以不破坏对象安全的方式完成这一切。

总而言之,声明为 [de]serializable 的 trait 的每个实现都在编译时注册,并且在运行时解决 trait 对象的 [de]serialization 的情况。

于 2019-09-06T08:24:25.347 回答
0

这样做的图书馆应该是可能的。要创建这样的库,我们将在使用库之前创建从 TypeId 到类型名称的双向映射,然后将其用于带有类型标记的序列化/反序列化。可以有一个函数来注册不属于你的包的类型,并提供一个宏注释来自动为你的包中声明的类型执行此操作。

如果有一种方法可以在宏中访问类型 ID,那将是在编译时而不是运行时检测 TypeId 和类型名称之间的映射的好方法。

于 2018-05-14T16:35:29.283 回答
0

您所有的库都可以提供一个注册例程,由 保护std::sync::Once,将一些标识符注册到一个 commonstatic mut中,但显然您的程序必须全部调用它们。

我不知道是否TypeId在具有不同依赖项的重新编译中产生一致的值。

于 2017-06-01T21:45:45.977 回答