1

I have the following struct Grid where I would like to have a mutable get function which returns mutable references to the underlying Cells: 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 Cells because that does not exist (undefined behavior). Whats the common idiom here?

Gabriel
  • 8,990
  • 6
  • 57
  • 101
  • 4
    There are some more advanced techniques to get around that (see [`split_at_mut`](https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut) for a safe solution, or just use `unsafe` and get a `*mut T`), however it is important to understand as a beginner that 99% of the time, *this is not the way to go*. Rethinking the design of your software is a better solution (at least in Rust, in this situation). – jthulhu Dec 27 '22 at 22:44
  • 1
    I'm agreeing with jthulu here. Try another approach that doesn't involve mutable references. Rust might seem overly restrictive if you try and go against the grain, but it has other approaches that work much better once you get in the right groove. For example, you could use a `RefCell` to hold values, allowing interior mutability on a non-`mut` reference, though I'd recommend wrapping that up in some kind of thin abstraction layer. Exposing bare `Cell` instances instead of, say, `CellRef(RefCell)`, confusing names aside, is a better approach if you want "direct" access. – tadman Dec 27 '22 at 22:48
  • About redesign, thats a good point, maybe I can just write all the modify functions on `neighbors` as functions on `Grid` itself so not really returning them. – Gabriel Dec 27 '22 at 22:48
  • 1
    Alternatively, let `Grid` be the entry point for all modifications. It's important in Rust to *only* hand out `mut` references when *absolutely* necessary as these can cause a whole world if hurt if you start handing them out casually. The Rust way here, honestly, is to not even hand out references at all, but instead return indexes to the cells, and for `Grid` to have some kind of `get()` function that can turn those indexes back into values. – tadman Dec 27 '22 at 22:50
  • 1
    For example, could you solve your problem via an "apply_to_neighbors" method that takes in a closure? – cadolphs Dec 28 '22 at 00:59
  • The closure then needs multiple mut refs from a `grid.cells: Vec` which I could solve by going over `get_many_mut` in https://stackoverflow.com/a/74705002/293195. If that is safe? – Gabriel Dec 29 '22 at 12:08

0 Answers0