How to idiomatically enforce field coverage at compile time?

62 points Jern_97

I am writing a Rust program with maximum maintainability in mind.
Let's say I have the following struct with a mutating function "modify()":

pub struct MyStruct{
    field1: i32,
    field2: f64,
    field3: String,
}

impl MyStruct{
    pub fn modify(&mut self){
        self.field1 += 1;
        self.field2 += 1.0;
        //field3 does not require modification
    }
}

Let's now imagine that somewhere in the future the functionality of the program needs to be expanded. Someone decides to add an extra field (field4) to the struct, but forgets to update the modify() function to also cover the new field:

pub struct MyStruct{
    field1: i32,
    field2: f64,
    field3: String,
    field4: u8
}

impl MyStruct{
    pub fn modify(&mut self){
        self.field1 += 1;
        self.field2 += 1.0;
        //field3 does not require modification
    }
}

This code still compiles, but if field4 also required modification, we have a problem.
Bugs like this are easily made, and can be hard to detect.
Therefore I would like to catch these bugs at compile time rather than at run time.
The compiler should force me to explicitly cover all fields in the modify() function, even it does not require any modification (like field3).

One possible solution I came up with is writing the modify() function in the following way:

impl MyStruct{
    pub fn modify(mut self) -> Self{
        Self{
            field1: self.field1 + 1,
            field2: self.field2 + 1.0,
            field3: self.field3
        }
    }
}

This code will not compile when new fields are added unless the modify function is also updated.

This works, but I have no idea if this is the best way to achieve this.
I also have am not sure if this "consuming" approach has a performance penalty compared to the mutable borrow.
I would actually prefer if this could be achieved using a mutable borrow.

Does anyone what this concept is called and how to achieve this in a clean and idiomatic way?

(hopefully my explanation was somewhat clear)