Borrow error when returning twice `self.X`

I have the following struct Grid where I would like to have a mutable get function which returns mutable references to the underlying Cell s: MWE here

struct Cell {
    c: i64,
}

struct Grid {
    a: [Cell; 3],
}

impl Grid {
    fn cell_i(&mut self, i: usize) -> &mut Cell {
        return &mut self.a[i];
    }
    
    fn neighbors(&mut self, _i: usize) -> (&mut Cell, &mut Cell) {
        return (self.cell_i(0), self.cell_i(2));
    }
}



fn main() {
    let a = &mut Grid {
            a: [Cell { c: 3 }, Cell { c: 4 }, Cell { c: 5 }],
        };
        
    let _bs = a.neighbors(1);
}

I am just puzzeled as a beginner, how to solve this? I need both neighbor cells mutable returned from neighbors , to make computations on them. I could return immutable but then I cannot turn them into &mut Cell s because that does not exist (undefined behavior). Whats the common idiom here?

You have multiple solutions with different levels of complexity and safety.

You could rely on internal mutability, which moves some of the lifetime checking to runtime, with the associated performance cost and some ergonomic costs, but this is usually a reasonable thing to do, particularly to unblock at first.

Another solution could be to rework your API to pass in closures for the mutation of the neighbors to get around the borrowing problems, but I wouldn't do this.

Finally, you can rely on unsafe, but you have to ensure that you're not running afoul of the Rust aliasing guarantees, similarly to how &mut [T]::split_at_mut(), but if you don't need this, given that you don't have experience dealing with unsafe, I'd stay away from it. Having said that, because split_at_mut already exists, you can use it.

The problem is that your getter borrows the entirety of self. You can't have overlapping &mut borrows, so you can't hold on to the results of two calls to cell_i.

(Getters and setters are less common in Rust due to borrowing issues like this; when they do still exist, you usually at least don't use them in the struct's own module. By the way, that particular getter could also be replaced with an implementation of IndexMut. Perhaps the methods named get (or get_mut) should check the bounds and return an Option.)

If you had two fields instead of one array with two members, Rust would understand (within a single function) that accessing each one individually can't create an overlap. But it doesn't understand that for different array indices, so you need the borrow splitting that @ekuber talked about. In this particular case, you can also use match on the array in neighbor. Or for the more general version, match on a slice.


Incidentally, Cell is a standard library type with a particular functionality; I suggest not using that name for your own struct.

1 Like