我正在学习 Rust,并且很难将我的 C++ 架构思维方式转变为 Rust 架构世界。目前,我正在努力定义特征的通用功能以避免代码重复。
问题
trait CommonFunctionality {
fn common_method(&self) -> i32;
}
trait SpecialFunctionality1 : CommonFunctionality {
fn special_foo(&self) -> i32; // defined in actual implementations
}
impl<T: SpecialFunctionality1> CommonFunctionality for T {
fn common_method(&self) -> i32 {self.special_foo()}
}
trait SpecialFunctionality2 : CommonFunctionality {
fn special_bar(&self) -> i32; // defined in actual implementations
}
impl<T: SpecialFunctionality2> CommonFunctionality for T {
fn common_method(&self) -> i32 {self.special_bar()}
}
我不想为我编写的每个实际结构实现
CommonFunctionality
。所以我有了在图书馆使用超级特征的想法。每个实现 SpecialFunctionality1
或 SpecialFunctionality2
的实际结构实现都可以获得 CommonFunctionality
,无需任何额外代码。不幸的是这不能编译。
编译器抛出:
error[E0119]: conflicting implementations of trait 'CommonFunctionality'
我发现了类似的问题描述,但其根本原因是类型无法区分,这里
impl<T: SpecialFunctionality1>
和 impl<T: SpecialFunctionality2>
显然是不同的类型(据我理解)。
当注释掉最后三行时,所有内容都会编译。
那么,谁能解释为什么这不能编译? 或者,有人对编码更好的模式有建议吗?
低效的解决方法
有效的是,当我仅针对其中一个专门特征实施
CommonFunctionality
时。
我的库中的特征可能如下所示:
trait CommonFunctionality {
fn common_method(&self) -> i32;
}
trait SpecialFunctionality1 : CommonFunctionality {
fn special_foo(&self) -> i32;
}
impl<T: SpecialFunctionality1> CommonFunctionality for T {
fn common_method(&self) -> i32 {self.special_foo()}
}
trait SpecialFunctionality2 : CommonFunctionality {
fn special_bar(&self) -> i32;
}
虽然
SpecialFunctionality1
的实际结构实现与 CommonFunctionality
完全解耦(同时仍然提供它):
struct MyStruct1 {
}
impl SpecialFunctionality1 for MyStruct1 {
fn special_foo(&self) -> i32 {46}
}
SpecialFunctionality2
的实际结构实现与CommonFunctionality
完全耦合:
struct MyStruct2 {
}
impl SpecialFunctionality2 for MyStruct1 {
fn special_bar(&self) -> i32 {36}
}
impl CommonFunctionality for MyStruct2 {
fn common_method(&self) -> i32 {self.special_bar()}
}
现在最后三行代码需要在从
SpecialFunctionality2
派生功能的每个实际结构中实现。这是低效的实施工作。更糟糕的是:每当 CommonFunctionality
发生变化时,我都必须重新设计所有结构。
没有什么可以阻止新特征或具体类型
FooBar
实现这两个特征 SpecialFunctionality1
和 SpecialFunctionality2
。
在这种情况下,编译器应该选择哪个专业化?是因为
FooBar
实现了 ...1
而发生的,还是因为 FooBar
实现了 ...2
? 发生的?
这就是错误的来源。
@john-kugelman 已经给出了一些想法:辅助方法和枚举。
您通常可以在枚举和特征之间做出设计决策,这取决于您的类型是否更可能详尽并由您(作为库的作者)或用户控制。
如果我上面提到的情况,即结构实现了这两个特殊功能特征,实际上永远不会发生,那么枚举听起来就很正确。
在其他情况下,获得代码重用的方法是通过
#[derive]
宏,但我没有任何实现该方法的经验。