What's the best way to refactor my code to implement composition in Rust?

Viewed 124

The following has a lot of duplicated code. What's the best way to refactor it?

I'm coming from JavaScript where I use composition to achieve the same result, but in Rust it seems to me that I have to reimplement a lot of code.

I know there is a way using macros, but if the logic is more complex I'll end up with a large executable file since macros are inlined.

struct Shape {
    x: i32,
    y: i32,
}

struct Circle {
    x: i32,
    y: i32,
    radious: i32,
}

struct Square {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

trait Advance {
    fn advance(&mut self);
}

impl Advance for Shape {
    fn advance(&mut self) {
        self.x += 1;
    }
}

impl Advance for Square {
    fn advance(&mut self) {
        self.x += 1;
    }
}

impl Advance for Circle {
    fn advance(&mut self) {
        self.x += 1;
    }
}

fn main() {
    println!("Hello World!!");

    let mut shape = Shape { x: 0, y: 0 };
    let mut square = Square {
        x: 0,
        y: 0,
        width: 10,
        height: 10,
    };
    let mut circle = Circle {
        x: 0,
        y: 0,
        radious: 5,
    };

    while shape.x < 10 {
        shape.advance();
        circle.advance();
        square.advance();
        println!("shape {}", shape.x);
        println!("circle {}", circle.x);
        println!("square {}", square.x);
        println!("---------------------");
    }
}

playground

1 Answers

There is no way to extend a struct, but you can put common properties into another struct and your struct can consist from these common structs. Common behaviors can be triggered via these common structs like Point.

#[derive(Default)]
struct Point {
    x: i32,
    y: i32,
}

struct Shape {
    point: Point,
}

struct Circle {
    point: Point,
    radious: i32,
}

struct Square {
    point: Point,
    width: i32,
    height: i32,
}

trait Advance {
    fn advance(&mut self);
}

impl Advance for Point {
    fn advance(&mut self) {
        self.x += 1;
    }
}

fn main() {
    let mut shape = Shape {
        point: Point::default(),
    };
    let mut square = Square {
        point: Point::default(),
        width: 10,
        height: 10,
    };
    let mut circle = Circle {
        point: Point::default(),
        radious: 5,
    };

    while shape.point.x < 10 {
        shape.point.advance();
        circle.point.advance();
        square.point.advance();
        println!("shape {}", shape.point.x);
        println!("circle {}", circle.point.x);
        println!("square {}", square.point.x);
        println!("---------------------");
    }
}

Playground

Related