1
votes

I have the following code (just an example) which can't satisfy the borrow checker. One method modifies one field of the struct and calls another method to modify the other. The problem is when calling the second method it needs a parameter that depends on the struct. The call to second method doesn't work with argument &self.a and neither &mut self.a because that would be a second mutable borrow.

In the end I fixed it by having all the code in just one method, but that's ugly as hell (in my real problem). How can this be solved? (I know the parameter &self.a is not required, but that's not the point I want to illustrate...)


struct ABC {
    a: Vec<i32>,    // no Copy trait
    b: i32,
}

impl ABC {
    fn new() -> ABC { ABC {a: vec![0,1], b: 10} }

    fn first(&mut self) {
        self.a.push(2);         // updates one field
        self.second(&self.a);   // uses a method to update the other field
    }

    fn second(&mut self, x: &Vec<i32>) {
        self.b += x[1];
    }
}

fn main() {
    let mut s = ABC::new();
    s.first();
}

Playground here.

1
You can make it a helper function fn second(y: &mut i32, x: &Vec<i32>) if you just want that part to be encapsulated.kmdreko

1 Answers

2
votes

You already borrowed from self.a; so as long as that borrow is there, you cannot move out to a second method. You can use to_vec() to copy the data to the second method.

struct ABC {
    a: Vec<i32>,    // no Copy trait
    b: i32,
}

impl ABC {
    fn new() -> ABC { ABC {a: vec![0,1], b: 10} }

    fn first(&mut self) {
        self.a.push(2);         // updates one field
        self.second(self.a.to_vec());
    }

    fn second(&mut self, x: Vec<i32>) {
        self.b += x[1];
    }
}

fn main() {
    let mut s = ABC::new();
    s.first();
}

playground

But as indicated, it will copy the data.

The simplest would be to update self.b in first method. In that way we don't borrow twice from self.a

    fn first(&mut self) {
        self.a.push(2);         // updates one field
        self.b += self.a[1];
    }

If second does not borrow from self, it will work as follow:

struct ABC {
    a: Vec<i32>, // no Copy trait
    b: i32,
}

impl ABC {
    fn new() -> ABC {
        ABC {
            a: vec![0, 1],
            b: 10,
        }
    }

    fn first(&mut self) {
        self.a.push(2); // updates one field
        Self::second(&mut self.b, &self.a);
    }
    fn second(y: &mut i32, x: &Vec<i32>) {
        *y += x[1];
    }
}

fn main() {
    let mut s = ABC::new();
    s.first();
}

But it is not much different from updating self.b directly in first method.