如何避免具有语义相等的字段/属性的不同结构的代码重复?

问题描述 投票:0回答:1

鉴于这两个结构:

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

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

由于我来自 Java,我会从中提取一个基类

ShapeRenderer
并将字段
canvas
origin
应用到其中,而特定类型将保留其名为
shape
的字段。对于这种情况,Rust 的最佳实践是什么,因为特征仅与接口类似,因此不允许属性/字段?

inheritance struct rust code-duplication
1个回答
16
投票

这看起来是泛型的完美案例。

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

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

请注意,我已通过特征

T
(您必须创建)来限制泛型类型
Shape
。您可以在此处设置您喜欢的任何限制(或根本没有限制),但您将仅限于使用这些特征的成员。

您希望能够在形状中访问的任何内容都需要通过

Shape
来暴露。例如,如果您需要中心和区域,那么特征定义可能如下所示:

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);

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

© www.soinside.com 2019 - 2024. All rights reserved.