我在我的宠物项目中有一个递归数据结构:
(这是一个简化的例子)
pub trait Condition {
fn validate(&self, s: &str) -> bool;
}
pub struct Equal {
ref_val: String,
}
impl Condition for Equal {
fn validate(&self, s: &str) -> bool { self.ref_val == s }
}
pub struct And<A, B> where A: Condition + ?Sized, B: Condition + ?Sized {
left: Box<A>,
right: Box<B>,
}
impl<A, B> Condition for And<A, B> where A: Condition + ?Sized, B: Condition + ?Sized {
fn validate(&self, s: &str) -> bool { self.left.validate(s) && self.right.validate(s) }
}
我想对条件特性进行序列化和反序列化(使用
serde
)。例如:fn main() {
let c = And {
left: Box::new(Equal{ ref_val: "goofy".to_string() }),
right: Box::new(Equal{ ref_val: "goofy".to_string() }),
};
let s = serde_json::to_string(&c).unwrap();
let d: Box<dyn Condition> = serde_json::from_string(&s).unwrap();
}
由于serde
无法直接反序列化动态特征,因此我标记了序列化的标记,例如:
#[derive(PartialEq, Debug, Serialize)]
#[serde(tag="type")]
pub struct Equal {
ref_val: String,
}
尝试实现Deserializer
和Vistor
以处理Box<dyn Condition>
由于我是Rust的新手,而且根据给定的文档实现Deserializer和Visitor并不那么直接,我想知道是否有人有更简单的方法来解决我的问题?
我已经阅读了serde文档,并在技术网站/论坛上寻找解决方案。我尝试了typetag,但它不支持泛型类型。
更新:
更准确地说:序列化工作正常,即serde可以序列化Condition trait的任何具体对象,但为了反序列化Condition,需要提供具体类型信息。但是这种类型信息在编译时不可用。我正在编写一个Web服务,客户可以上传用于上下文匹配(即条件)的规则,因此当需要反序列化条件时,Web服务的控制器不知道类型。例如,客户可以发布:
{"type":"Equal","ref_val":"goofy"}
或者
{"type":"Greater","ref_val":"Pluto"}
或者更复杂,包含任何组合器(“and”,“or”,“not”)
{"type":"And","left":{"type":"Greater","ref_val":"Gamma"},"right":{"type":"Equal","ref_val":"Delta"}}
因此,我需要使用序列化标记中的类型标签将其反序列化为一个特质(dyn Condition)。
typetag
这个 crate 是由 dtolnay 开发的,它可以让你实现这一点。 - EvilTak暂时不支持通用实现的反序列化;请使用 #[typetag::serialize] 生成仅序列化的代码
... - Da_Niel