简体   繁体   English

如果有的话,如何在Rust中添加多态特征对象的反序列化?

[英]How can deserialization of polymorphic trait objects be added in Rust if at all?

I'm trying to solve the problem of serializing and deserializing Box<SomeTrait> . 我正在尝试解决序列化和反序列化Box<SomeTrait> I know that in the case of a closed type hierarchy, the recommended way is to use an enum and there are no issues with their serialization, but in my case using enums is an inappropriate solution. 我知道在封闭类型层次结构的情况下,推荐的方法是使用枚举,并且序列化没有问题,但在我的情况下使用枚举是不合适的解决方案。

At first I tried to use Serde as it is the de-facto Rust serialization mechanism. 起初我尝试使用Serde,因为它是事实上的Rust序列化机制。 Serde is capable of serializing Box<X> but not in the case when X is a trait. Serde能够序列化Box<X>但不能在X是特征的情况下。 The Serialize trait can't be implemented for trait objects because it has generic methods. 无法为特征对象实现Serialize特征,因为它具有泛型方法。 This particular issue can be solved by using erased-serde so serialization of Box<SomeTrait> can work. 这个特殊问题可以通过使用擦除serde来解决,因此Box<SomeTrait>序列化可以工作。

The main problem is deserialization. 主要问题是反序列化。 To deserialize polymorphic type you need to have some type marker in serialized data. 要反序列化多态类型,您需要在序列化数据中使用某种类型标记。 This marker should be deserialized first and after that used to dynamically get the function that will return Box<SomeTrait> . 该标记应首先反序列化,然后用于动态获取将返回Box<SomeTrait>的函数。

std::any::TypeId could be used as a marker type, but the main problem is how to dynamically get the deserialization function. std::any::TypeId可以用作标记类型,但主要问题是如何动态获取反序列化函数。 I do not consider the option of registering a function for each polymorphic type that should be called manually during application initialization. 我不考虑为应用程序初始化期间应手动调用的每种多态类型注册函数的选项。

I know two possible ways to do it: 我知道有两种可能的方法:

  1. Languages that have runtime reflection like C# can use it to get deserialization method. 具有C#等运行时反射的语言可以使用它来获取反序列化方法。
  2. In C++, the cereal library uses magic of static objects to register deserializer in a static map at the library initialization time. 在C ++中,谷歌库使用静态对象的魔法在库初始化时在静态映射中注册反序列化器。

But neither of these options is available in Rust. 但Rust中没有这些选项。 How can deserialization of polymorphic objects be added in Rust if at all? 如果有的话,如何在Rust中添加多态对象的反序列化?

This has been implemented by dtolnay . 这已由dtolnay实施

The concept is quite clever ans is explained in the README : 这个概念非常聪明,在README有解释:

How does it work? 它是如何工作的?

We use the inventory crate to produce a registry of impls of your trait, which is built on the ctor crate to hook up initialization functions that insert into the registry. 我们使用inventory箱来生成您的特征的impl注册表,该注册表构建在ctor包装箱上以挂接插入注册表的初始化函数。 The first Box<dyn Trait> deserialization will perform the work of iterating the registry and building a map of tags to deserialization functions. 第一个Box<dyn Trait>反序列化将执行迭代注册表和构建反序列化函数的标记映射的工作。 Subsequent deserializations find the right deserialization function in that map. 随后的反序列化在该映射中找到正确的反序列化函数。 The erased-serde crate is also involved, to do this all in a way that does not break object safety. erased-serde箱也参与其中,以不破坏物体安全的方式完成所有这些操作。

To summarize, every implementation of the trait declared as [de]serializable is registered at compile-time, and this is resolved at runtime in case of [de]serialization of a trait object. 总而言之,声明为[de] serializable的特征的每个实现都是在编译时注册的,并且在特征对象的[de]序列化的情况下在运行时解析。

All your libraries could provide a registration routine, guarded by std::sync::Once , that register some identifier into a common static mut , but obviously your program must call them all. 所有的库都可以提供一个注册例程,由std::sync::Once ,它将一些标识符注册到一个普通的static mut ,但显然你的程序必须全部调用它们。

I've no idea if TypeId yields consistent values across recompiles with different dependencies. 我不知道TypeId是否会在具有不同依赖关系的重新编译中产生一致的值。

A library to do this should be possible. 应该可以实现这样做的库。 To create such a library, we would create a bidirectional mapping from TypeId to type name before using the library, and then use that for serialization/deserialization with a type marker. 要创建这样的库,我们将在使用库之前创建从TypeId到类型名称的双向映射,然后使用它来对类型标记进行序列化/反序列化。 It would be possible to have a function for registering types that are not owned by your package, and to provide a macro annotation that automatically does this for types declared in your package. 可以使用一个函数来注册不属于您的包的类型,并提供一个宏注释,该注释会自动为包中声明的类型执行此操作。

If there's a way to access a type ID in a macro, that would be a good way to instrument the mapping between TypeId and type name at compile time rather than runtime. 如果有一种方法可以访问宏中的类型ID,那么这将是在编译时而不是运行时检测TypeId和类型名称之间的映射的好方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 杰克逊为多态对象定制反序列化 - Jackson custom deserialization for polymorphic objects 多个多态对象序列化/反序列化模式 - Multiple polymorphic objects serialization/deserialization pattern 如何使用Java和Jackson Library对Json String进行多态反序列化? - How can I polymorphic deserialization Json String using Java and Jackson Library? C#对象的多态XML序列化/反序列化,用于各种节点列表 - Polymorphic XML Serialization/DeSerialization to C# objects for varying list of nodes 如何防止-Xcheckinit干扰Scala对象的反序列化? - How can I keep -Xcheckinit from interfering with the deserialization of Scala objects? Java多态Json反序列化 - Java Polymorphic Json Deserialization 多态XML序列化/反序列化 - Polymorphic XML serialization/deserialization 如何正确制作对象列表的列表(主要),以便将项目添加到列表时,不会将其添加到列表(主要)中的所有列表? - How can I make a List(main) of Lists of Objects correctly so that when an item is added to a list, it is not added to all the lists in the List(main)? 在给定XSD的情况下,如何在C#中进行多态反序列化? - How to do a polymorphic deserialization in C# given a XSD? Kotlin 多态反序列化不反序列化值 - Kotlin Polymorphic deserialization not deserializing values
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM