根本如何在Rust中添加多态性状对象的反序列化? [英] How can deserialization of polymorphic trait objects be added in Rust if at all?

查看:293
本文介绍了根本如何在Rust中添加多态性状对象的反序列化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

起初,我尝试使用Serde,因为它是事实上的Rust序列化机制. Serde能够序列化Box<X>,但在X是特征时不能. Serialize 特征不能用于特征对象,因为它具有通用性方法.此特定问题可以通过使用 erased-serde 来解决,以便可以对Box<SomeTrait>进行序列化./p>

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

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

我知道两种可行的方法:

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

但是这些选项在Rust中都不可用.根本如何在Rust中添加多态对象的反序列化?

解决方案

这是由dtolnay实现的.

README中对此概念进行了巧妙的解释:

它如何工作?

我们使用 inventory 板条箱来生成具有您特质的impls的注册表建立在 ctor 板条箱中,以挂接插入注册表中的初始化函数.第一个Box<dyn Trait>反序列化将执行迭代注册表并为反序列化功能建立标签映射的工作.随后的反序列化可以在该图中找到正确的反序列化功能.还涉及到 erased-serde 板条箱,以不中断的方式完成所有操作对象安全.

总而言之,声明为[de] serializable的trait的每个实现都在编译时进行注册,如果对trait对象进行[反]序列化,则可以在运行时解决.

I'm trying to solve the problem of serializing and deserializing 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 is capable of serializing Box<X> but not in the case when X is a trait. The Serialize trait can’t be implemented for trait objects because it has generic methods. This particular issue can be solved by using erased-serde so serialization of Box<SomeTrait> can work.

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>.

std::any::TypeId could be used as a marker type, but the main problem is how to dynamically get the deserialization function. 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.
  2. In C++, the cereal library uses magic of static objects to register deserializer in a static map at the library initialization time.

But neither of these options is available in Rust. How can deserialization of polymorphic objects be added in Rust if at all?

解决方案

This has been implemented by dtolnay.

The concept is quite clever ans is explained in the 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. The first Box<dyn Trait> deserialization will perform the work of iterating the registry and building a map of tags to deserialization functions. 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.

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.

这篇关于根本如何在Rust中添加多态性状对象的反序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆