xet*_*a11 2 inheritance struct code-duplication rust
鉴于以下两个结构:
pub struct RectangleRenderer {
canvas: Canvas,
origin: Point,
shape: Rectangle,
}
pub struct CircleRenderer {
canvas: Canvas,
center: Point,
shape: Circle,
}
Run Code Online (Sandbox Code Playgroud)
由于我来自爪哇,我会从中提取基类ShapeRenderer淘汰者和应用领域canvas,并origin到,虽然具体类型将继续把他们的领域shape。在这种情况下,Rust的最佳实践是什么,因为特征仅起到类似于界面的作用,因此不允许属性/字段?
对于仿制药来说,这似乎是一个完美的案例。
您可以像这样制作单个结构:
struct ShapeRenderer<T: Shape> {
canvas: Canvas,
origin: Point,
shape: T,
}
Run Code Online (Sandbox Code Playgroud)
请注意,我已将通用类型限制T为特征Shape(必须创建)。您可以在此处放置任何喜欢的界限(或完全没有界限),但是将只能使用这些特征的成员。
您希望能够访问形状中的任何内容都需要通过公开Shape。例如,如果您需要中心和区域,那么特征定义可能看起来像这样:
trait Shape {
fn center(&self) -> (f64, f64);
fn area(&self) -> f64;
}
Run Code Online (Sandbox Code Playgroud)
如果这还不够灵活,您还可以ShapeRenderer仅对特定形状给出特殊的行为。例如:
impl ShapeRenderer<Rectangle> {
fn n_sides(&self) -> u32 {
4
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,在其中impl,我们可以访问的所有字段Rectangle,而不仅限于中的功能Shape。
另外,您可以创建一个基本结构,然后将其作为最终结构的成员:
struct Renderer {
canvas: Canvas,
origin: Point,
}
struct CircleRenderer {
renderer: Renderer,
shape: Circle,
}
struct RectangleRenderer {
renderer: Renderer,
shape: Rectangle,
}
Run Code Online (Sandbox Code Playgroud)
这是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);
Run Code Online (Sandbox Code Playgroud)
虽然泛型示例最复杂,但是它也最强大和灵活。它使您可以轻松地在结构之间共享代码,同时还使您拥有特定于某个代码的代码,从而可以访问其所有字段。