3

I have the following code:

#[derive(Clone, Copy)]
struct Point {
    x: f64,
    y: f64,
    z: f64
}

impl Point {
    fn set_z(&self, val: f64) -> Point {
        Point{x: self.x, y: self.y, z: val}
    }
}

struct Boo {
    point: Point
}

impl Boo {
    fn point(&self) -> &Point { &self.point }
    fn set_point(&mut self, val: &Point) { self.point = *val; }
}

fn main() {
    let mut boo = Boo{point:Point{x: 0., y: 0., z: 0.}};
    let new_p = boo.point().set_z(17.);
    boo.set_point(&new_p);
}

In fact, I have bunch of structures like Boo with Point fields, and often enough I need to change only one field in it.

So I can

  1. Implement millions of methods like:

    impl Boo {
        fn set_x(&mut self, val: f64) { self.point.x = val; }
        fn set_y(&mut self, val: f64) { self.point.y = val; }
        //...
    }
    

    Which is too boring, and if have two, three fields like point1, point2 and so on I will be buried under tons of these methods.

  2. The method described at the top of the question looks nicer because I need only two methods per field, but I have to make modification in two steps: get point and set point.

So the ideal method for me would look like this:

boo.set_point(boo.point().set_z(17.));

But this is impossible, because to implement this I need to somehow read and write references at the same time.

How can I simplify setting only one field of Point for users of my module?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1244932
  • 7,352
  • 5
  • 46
  • 103
  • It feels that if you have so many types that need to do the same thing, then you actually have one type that should have many instances. – Shepmaster Aug 15 '16 at 22:37
  • You can change your impl Point like this: ```impl Point { fn set_z(&self, val: f64) -> Point { Point{z: val, *self} } ``` – S.R Jan 25 '18 at 10:48
  • In topic, I think you could write own `derive` that will implement `set_x`, `set_z` functions in `Boo` for you. But I am just a begginer and can't help you with example. – S.R Jan 25 '18 at 10:50

1 Answers1

5

Why don't you make those fields public?

#[derive(Clone, Copy)]
struct Point {
    pub x: f64,
    pub y: f64,
    pub z: f64
}

struct Boo {
    pub point: Point
}

boo.point.z = 17.0;

Encapsulation is a good thing and you often don't want everyone to change the internal fields of a type. But this is only necessary if there are illegal values the field mustn't take on or if other values are dependent on that field (e.g. caches). But if that's not the case -- and in your example it doesn't look like it is -- then just mark those fields as public.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305