当 Rust 没有继承时,如何编写处理版本化数据的函数?



我有使用SemVer进行版本控制的数据。我有一些函数有SemVer的要求,例如它们支持半开放区间的版本[1.1,2.0(。在C++中,我可以做这样的事情:

struct Data_v1_0 {
// Added in V1.0
int a;
};
struct Data_v1_1 : public Data_v1_0 {
// Added in V1.1
int b;
}
void foo(const Data_v1_0& data) {
// Supports [1.0, 2.0)
print(data.a);
}
void bar(const Data_v1_1& data) {
// Supports [1.1, 2.0)
print(data.b);
}

在Rust中有类似的方法吗?

您可以使用特征:

trait DataV1_0 {
fn a(&self) -> i32;
}
trait DataV1_1: DataV1_0 {
fn b(&self) -> i32;
}
struct Data {
a: i32,
b: i32,
}
impl DataV1_0 for Data {
fn a(&self) -> i32 {
self.a
}
}
impl DataV1_1 for Data {
fn b(&self) -> i32 {
self.b
}
}
fn foo(data: &dyn DataV1_0) {
println!("a: {}", data.a());
}
fn bar(data: &dyn DataV1_1) {
println!("b: {}", data.b());
}

我们使用trait继承来替换这里的结构,并使用trait方法来访问字段。我的示例是只读的,但您也可以实现setter方法。

另一个解决方案是像在C中那样实现继承。我并不是说你应该这样做,但这是一种需要考虑的可能性:

pub struct Data_v1_0 {
// Added in V1.0
a: i32,
}
impl Data_v1_0 {
fn a(&self) -> i32 {
self.a
}
fn set_a(&mut self, a: i32) {
self.a = a
}
}
pub struct Data_v1_1 {
extends: Data_v1_0,
// Added in V1.1
b: i32,
}
impl Data_v1_1 {
fn b(&self) -> i32 {
self.b
}
fn set_b(&mut self, b: i32) {
self.b = b
}
}
impl Deref for Data_v1_1 {
type Target = Data_v1_0;
fn deref(&self) -> &Self::Target {
&self.extends
}
}
impl DerefMut for Data_v1_1 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.extends
}
}

由于有了DerefDerefMut,您可以在Data_v1_1的实例上调用a()set_a()。然而,用完全限定的语法(例如Data_v1_1::a(data)(调用它是不可能的,因此用Data_v1_1替换Data_v1_0将是API的突破性变化。

最新更新