我有一个与描述的类似的用例 here ,但略有不同,因为我的解决方案无法用非泛型方法替换泛型方法。这是我的代码(Rust Playground):
use serde::{de::DeserializeOwned, Serialize};
use serde_json;
trait Serializer {
fn serialize_data<V>(&self, data: &V) -> Result<String, String> where V: Serialize;
fn deserialize_data<V>(&self, ser_data: &str) -> Option<V> where V: DeserializeOwned;
}
struct JsonSerializer {
x: i32 // some member I need to store
}
impl JsonSerializer {
fn new() -> JsonSerializer {
JsonSerializer { x: 1 }
}
}
impl Serializer for JsonSerializer {
fn serialize_data<V>(&self, data: &V) -> Result<String, String> where V: Serialize {
match serde_json::to_string(data) {
Ok(ser_data) => Ok(ser_data),
Err(err) => Err(err.to_string())
}
}
fn deserialize_data<V>(&self, ser_data: &str) -> Option<V> where V: DeserializeOwned {
match serde_json::from_str(ser_data).unwrap() {
Ok(val) => Some(val),
Err(_) => None
}
}
}
// I may want to have more serializer objects like
// YamlSerizlier, BincodeSerializer and so on...
// ...
struct MyMainObject {
serializer: Box<Serializer>
}
impl MyMainObject {
fn new() -> MyMainObject {
MyMainObject { serializer: Box::new(JsonSerializer::new()) }
}
fn do_something(&self) {
println!("{}", self.serializer.serialize_data(&1));
println!("{}", self.serializer.serialize_data(&String::from("MY STRING")));
}
}
fn main() {
let my_main_object = MyMainObject::new();
my_main_object.do_something();
}
如上一个问题所述,编译此代码时出现错误特征 `Serializer` 无法制作为对象
,因为它具有通用方法:
Compiling playground v0.0.1 (/playground)
error[E0038]: the trait `Serializer` cannot be made into an object
--> src/main.rs:42:5
|
42 | serializer: Box<Serializer>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Serializer` cannot be made into an object
|
= note: method `serialize_data` has generic type parameters
= note: method `deserialize_data` has generic type parameters
但就我而言,我希望这些方法保持通用,以便我可以序列化/反序列化任何类型的数据。
所以我的问题是如何保持动态调度模式并仍然使其工作,这意味着我想要 MyMainObject
中的 Serializer
特征成员,我可以使用任何初始化序列化器对象的类型(Json、Yaml 等),然后在 MyMainObject
内部调用 serializer.serialize_data()
或 serializer.deserialize_data()
>.
如果这不可能,您可以建议的最佳替代方案是什么?
编辑:
我需要一个适用于不同类型序列化器的解决方案,列出这些序列化器:
最佳答案
注意
以下并不是一个好的长期解决方案,它只是一个解决方法。做你想做的事情的正确方法是找出并实现一种协调方法 bincode
和serde_yaml
与 erased_serde
。但如果您现在需要它工作,这里是
要点
基本上,您可以使用枚举来编写穷人的动态调度。它看起来或多或少像这样(我简化并省略了一些东西):
struct JsonSerializer();
struct YamlSerializer();
trait Serializer {
fn serialize<V>(&self, thing: &V) -> ();
}
impl Serializer for JsonSerializer {
fn serialize<V>(&self, thing: &V) -> () {
println!("json");
}
}
impl Serializer for YamlSerializer {
fn serialize<V>(&self, thing: &V) -> () {
println!("yaml");
}
}
// That's what we'll be using instead of Box<dyn Serializer>
enum SomeSerializer {
Json(JsonSerializer),
Yaml(YamlSerializer),
}
impl SomeSerializer {
pub fn serialize<V>(&self, thing: &V) -> () {
match self {
SomeSerializer::Json(ser) => ser.serialize(thing),
SomeSerializer::Yaml(ser) => ser.serialize(thing),
}
}
}
以下是您如何使用它(除非您可能需要此处的实际构造函数):
pub fn main() {
let thing = 2;
let json = SomeSerializer::Json(JsonSerializer());
let yaml = SomeSerializer::Yaml(YamlSerializer());
json.serialize(&thing);
yaml.serialize(&yaml);
}
这有严重的缺点(见下文),但它确实允许您将具有通用方法的东西打包到统一的接口(interface)中。
问题
这种方法的主要问题是很难向设置中添加新的序列化器。与Box<dyn Serializer>
您需要做的就是impl Serializer
为了某件事。在这里,您必须向枚举添加一个变体,并在所有相关方法中对其进行模式匹配。这在 SomeSerializer
的 crate 中很不方便。已定义,并且在其他 crate 中不可能。此外,向公共(public)枚举添加变体是一项重大更改,下游 crates 可能并不完全欢迎。有一些方法可以在一定程度上改善这种情况:
隐藏 SomeSerializer
这对于SomeSerializer
来说并没有什么意义。公开。在其上进行模式匹配的能力几乎没有什么好处,并且它是公开的,这限制了您在不破坏下游事物的情况下可以对其进行的操作。通常的解决方案是将其放入不透明的结构中并将其导出,从而隐藏枚举本身:
pub struct VisibleSerializer(SomeSerializer);
仍然使用该特征
您无法扩展SomeSerializer
在其他 crate 中带有额外的序列化器。您可以继续在其上安装更多枚举层(这既不幸又丑陋),但是原始 crate 中的任何函数都不会接受这种构造。这可以有所帮助:而不是制作 serialize
SomeSerializer
的固有方法,实现Serializer
为它,并创建所有将使用 SomeSerializer
的函数通用并接受 T: Serializer
。突然间,所有下游 crates 都可以在设置中添加他们想要的序列化器。
仅特殊情况特殊情况
以这种方式包装超过四分之三的序列化程序有点荒谬,更不用说尴尬了。但是,如果您想要使用的大多数序列化器实际上是 erased_serde
-兼容,您可以在 SomeSerializer
中为它们提供一种包罗万象的枚举变体,并且仅针对不兼容的版本有单独的变体:
enum SomeSerializer {
Whatever(Box<dyn erased_serde::Serializer>),
}
关于generics - 具有通用方法的特征的动态调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54360326/