Borrowing issues mutating an attribute

Hello,

I found myself running into the following problem several times: I'd like to mutate an attribute within a method, using a closure which calls a second method. Consider the following example.

struct Adder {
    value: f64,
    some_vector: Vec<f64>,
}

impl Adder {

    fn add(&self, x: f64) -> f64 {
        x + self.value
    }

    fn modify_attribute(&mut self) {
        let f = |x: f64| self.add(x);
        self.some_vector.iter_mut().for_each(|x| *x = f(*x));
    }
}

The method modify_attribute uses the closure

f = |x: f64| self.add(x)

borrowing self immutably. However, then self.some_vector is borrowed mutably, which is not possible. In some cases, it is possible to get around the issue by defining the function outside of the structure, and cloning the necessary parameters.

impl Adder {
    fn modify_attribute(&mut self) {
        let value = self.value.clone();
        let f = |x: f64| add(value, x);
        self.some_vector.iter_mut().for_each(|x| *x = f(*x));
    }
}

fn add(value: f64, x: f64) -> f64 {
    value + x
}

However this is not always possible (when cloning is expensive), and I'd like to keep the logic of the function within my structure if possible. Is there a standard way to solve this problem ?

Partial (i.e. field-wise) borrows can solve this. Rewrite the add function such that it only borrows self.value instead of the entirety of self (playground).

If you find it annoying to use the newfound add() function in this manner, you can write a helper/wrapper around it that again borrows the entire self, and which you can then use more conveniently in other cases where that is not a problem.

Thanks ! The following works.

impl Adder {
    fn add(x: f64, value: f64) -> f64 {
        x + value
    }

    fn compute_something(&mut self) {
        let value = self.value;
        let f = |x: f64| Self::add(x, value);
        self.some_vector.iter_mut().for_each(|x| *x = f(*x));
    }
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.