我正在编写一个 Rust 板条箱,其中有一个结构体,其字段实现了一个特征,并且我想提供一个功能:
#[cfg(not(feature = "dyn"))]
:结构字段是T
静态分派的(性能更高,但运行时灵活性较差)#[cfg(feature = "dyn")]
:结构字段是Box<dyn MyTrait>
,动态分派的特征对象(运行时灵活性,性能成本较低)
trait MyTrait {}
#[cfg(not(feature = "dyn"))]
struct MyStruct<T: MyTrait> {
my_field: T
}
#[cfg(feature = "dyn")]
struct MyStruct {
my_field: Box<dyn MyTrait>
}
我的问题是,每一个impl
块都需要完全复制,但更改只会影响几行。
#[cfg(not(feature = "dyn"))]
impl<T: MyTrait> MyStruct<T> {
fn new(field: T) -> Self {
Self { field }
}
}
#[cfg(feature = "dyn")]
impl MyStruct {
fn new(field: impl MyTrait + 'static) -> Self {
Self { field: Box::new(field) }
}
}
有没有更优雅的方式来做到这一点?宏黑魔法?这只是一个坏主意,不值得做吗?
编辑
根据@cdhowie 的回复
这几乎可以成功编译!但是MyTrait
实际上有一个方法(我将其删除以获得一个最小示例):
trait MyTrait: Sized {
fn calculate(&self, struct: &MyStruct<Self>);
}
&MyStruct<Self>
由于此方法需要访问数据进行计算,因此引用是必要的。
尝试按照建议执行,但不起作用……这会破坏动态兼容性
impl MyTrait for Box<dyn MyTrait> {
// ^^^^^^^^^^^^^^^^
// ERROR
// the trait `MyTrait` cannot be made into an object
如果我尝试实现 Box 的特征(不确定这是否能解决我的问题),那么麻烦就来了:
impl<T: MyTrait> MyTrait for Box<T> {
fn calculate(
&self,
struct: &MyStruct<Self>,
) {
(**self).calculate(struct)
// ^^^^^^
// ERROR: mismatched types
// expected reference &MyStruct<T>
// found reference &MyStruct<Box<T>>
}
}