【问题标题】:How to avoid code duplication of different structs with semantically equal fields/properties?如何避免具有语义相同的字段/属性的不同结构的代码重复?
【发布时间】:2016-09-10 18:22:23
【问题描述】:

鉴于这两个结构:

pub struct RectangleRenderer {
    canvas: Canvas,
    origin: Point,
    shape: Rectangle,
}

pub struct CircleRenderer {
    canvas: Canvas,
    center: Point,
    shape: Circle,
}

由于我来自 Java,我会从中提取一个基类 ShapeRenderer 并将字段 canvasorigin 应用到其中,而特定类型将保留其名为 shape 的字段。对于这种情况,Rust 中的最佳实践是什么,因为特征只与接口类似,因此不允许使用属性/字段?

【问题讨论】:

  • 我发现了一个类似的问题,其中一个答案是关于作文的 -> stackoverflow.com/questions/32736170/… .
  • 或者我们可以有一个struct Renderer<Shape>
  • @kennytm 我不会说那是“另类” - 那是 组合!
  • @xetra11 为什么不用enum ShapeShapeRenderershape: Shape
  • @ljedrz 枚举带有运行时开销,而泛型则没有。我不确定这在这里是否很重要,但是(不知道更多),在我看来,这对于泛型来说是一个完美的地方。

标签: inheritance struct rust code-duplication


【解决方案1】:

这看起来是generics 的完美案例。

你可以像这样创建一个结构体:

struct ShapeRenderer<T: Shape> {
    canvas: Canvas,
    origin: Point,
    shape: T,
}

请注意,我已通过特征 Shape(您必须创建)来限制泛型类型 T。您可以在此处设置任何您喜欢的边界(或根本没有边界),但您将被限制使用这些特征的成员。

您希望能够在您的形状中访问的任何内容都需要通过Shape 公开。例如,如果您需要中心和区域,则 trait 定义可能如下所示:

trait Shape {
    fn center(&self) -> (f64, f64);
    fn area(&self) -> f64;
}

如果这还不够灵活,您还可以为 ShapeRenderer 提供仅针对特定形状的特殊行为。例如:

impl ShapeRenderer<Rectangle> {
    fn n_sides(&self) -> u32 {
        4
    }
}

请注意,在这个impl 中,我们可以访问Rectangle 的所有字段,而不仅仅是Shape 中的函数。


或者,您可以创建一个基本结构,然后将其作为最终结构的成员包含在内:

struct Renderer {
    canvas: Canvas,
    origin: Point,
}

struct CircleRenderer {
    renderer: Renderer,
    shape: Circle,
}

struct RectangleRenderer {
    renderer: Renderer,
    shape: Rectangle,
}

这是 Rust 中最接近标准继承的东西。


第三,如果您在创建这些结构时只关心代码重复并且不希望它们共享除字段以外的任何内容,您可以使用宏:

macro_rules! make_renderer {
    ($name: ty, $shape: ty) => (
        struct $name {
            canvas: Canvas,
            origin: Point,
            shape: $shape,
        }
    );
}

make_renderer!(CircleRenderer, Circle);
make_renderer!(RectangleRenderer, Rectangle);

虽然泛型示例是最复杂的,但它也是最强大和最灵活的。它使您可以轻松地在结构之间共享代码,同时还可以让您拥有特定于一个可以访问其所有字段的代码。

【讨论】:

  • 其实我更多的是寻找一些只会减少字段本身的代码重复的东西。就像有一个结构 ShapeRenderer 包含 canvasorigin 字段,然后是一个名为 RectangleRenderer 的具体结构,它包含 shape 字段,但也 inherits @ 的字段987654340@ - 类似于 Java 的继承 RectangleRenderer extends ShapeRenderer。 Traits 只能让我选择抽象函数/方法,而不是字段。
  • @xetra11 你也可以使用宏来减少代码重复users.rust-lang.org/t/…
  • @xetra11 这确实减少了重复。我认为您只是习惯于 Java 风格的继承,但这是一个偏好问题;我个人很高兴 Rust 没有它。
  • 嗯,好吧,也许我真的太习惯 Java 了。那么有没有其他方法可以避免非方法结构的重复呢?
  • @xetra11 我在答案中添加了另外两种方法。
猜你喜欢
  • 2019-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多