我正在为Rust构建一个Raft一致性算法中间件,其架构与copycat类似。我为开发人员编写了一个宏来定义命令方案。宏为用户定义的命令生成具有A
函数的特征dispatch
,这需要开发人员为其行为实现结构,并且编码器/解码器与此主题无关。
特征对象向Server
对象注册以使其有效。因为trait A
是动态生成的,所以我必须将另一个特征B
定义为A
的父特征。 Server
与B
配合使用,可以调用dispatch
中定义的A
函数。
我尝试了不同的组合,但没有一个有效。
trait B {
fn dispatch(&mut self, fn_id: u64) -> Vec<u8>;
}
// macro generated trait
trait A: B {
fn a(&self) -> Vec<u8>;
fn b(&self) -> Vec<u8>;
fn dispatch(&mut self, fn_id: u64) -> Vec<u8> {
match fn_id {
1 => a(),
2 => b(),
_ => {}
}
}
}
不幸的是,dispatch
中的A
功能无法在dispatch
中实现B
。当我实现A
的结构时,编译器仍然要求为dispatch
实现B
。
我还尝试将特征dispatch
中的B
移动到另一个特征作为B
的父特征,但该特征无法实现A
。
我还审核了https://github.com/rust-lang/rfcs/issues/1024。似乎问题是开放的,但已被抛弃。有没有其他方法可以使这种模式有效?
答案 0 :(得分:6)
您根本不需要B
成为A
的超级用户。您可以为任何B
添加T: A
的一揽子实施。我认为这更接近意图。
解释Rust代码:
trait A: B {
&#34;您可以实施A
,但前提是您已实施B
。&#34;
trait A {
//...
}
impl<T: A> B for T {
&#34;如果您实施A
,这里是B
的免费实施。&#34;
这是完整版:
trait B {
fn dispatch(&mut self, fn_id: u64) -> Vec<u8>;
}
// macro generated trait
trait A {
fn a(&self) -> Vec<u8>; // added &self
fn b(&self) -> Vec<u8>;
}
impl<T: A> B for T {
fn dispatch(&mut self, fn_id: u64) -> Vec<u8> {
match fn_id {
1 => self.a(),
2 => self.b(),
_ => panic!(), // Needed so that match cases are exhaustive
}
}
}
struct S {}
impl A for S {
fn a(&self) -> Vec<u8> {
unimplemented!()
}
fn b(&self) -> Vec<u8> {
unimplemented!()
}
}