Is using to_owned () an idiomatic way to update a struct in place?

I have been playing around with updating the Rust framework using chained methods. I found a way to do this, but I wasn't sure if my code below was idiomatic Rust versus just a workaround.

Specifically, I used .to_owned()

at the end of the chained method to return a borrowed structure. The code compiles and works fine. Here's a minimal example.

//struct.rs
#[derive(Debug, Default, Clone, PartialEq)]
pub struct ModelDataCapture {
    run: i32,
    year: i32,
}
impl ModelDataCapture {
    pub fn new() -> Self {
        ModelDataCapture::default()
    }
    pub fn set_run(&mut self, run: i32) -> &mut ModelDataCapture {
        self.run = run;
        self
    }
    pub fn set_year(&mut self, year: i32) -> &mut ModelDataCapture {
        self.year = year;
        self
    }
}

//main.rs
let data_capture = ModelDataCapture::new()
    .set_run(0)
    .set_year(1)
    .to_owned(); // <<< QUESTION

println!("here is the data capture {:?}", data_capture);

      

Is it correct to write this structure modification in place? If I have not included the method .to_owned()

at the end of the chain, compilation will fail with the message that the temporary variable has not been long enough.

+3


source to share


1 answer


Your code "works" but doesn't make sense to me. It:

  • Creates a value
  • Mutates meaning
  • Cloning a value
  • Discards the original value

See inefficiency? In addition, all "mutation in place" is completely discarded, so there is no benefit to it.

I would generally introduce a binding to mutate:

let mut data_capture = ModelDataCapture::new();
data_capture.set_run(0).set_year(1);

      



Or go in full and create a builder that has some equivalent finish

orbuild

#[derive(Debug)]
struct ModelDataCapture {
    run: i32,
    year: i32,
}

#[derive(Debug, Default)]
struct ModelDataCaptureBuilder {
    run: i32,
    year: i32,
}

impl ModelDataCaptureBuilder {
    fn set_run(self, run: i32) -> Self {
        ModelDataCaptureBuilder { run, ..self }
    }

    fn set_year(self, year: i32) -> Self {
        ModelDataCaptureBuilder { year, ..self }
    }

    fn build(self) -> ModelDataCapture {
        let ModelDataCaptureBuilder { run, year } = self;
        ModelDataCapture { run, year }
    }
}

fn main() {
    let data_capture = ModelDataCaptureBuilder::default().set_run(0).set_year(1).build();

    println!("here is the data capture {:?}", data_capture);
}

      

See Do Rust Builder templates need to use redundant structure code? for more examples of builders that reflect inline elements.

In the first example, you can take value self

by value, but in most cases this is annoying, since you always have to remember to bind the result.

+3


source







All Articles