#Closure problems

14 messages · Page 1 of 1 (latest)

night idol
#

I'm working with a lot of 2d vectors, and it gets annoying to write

        for y in (0..self.array.len()).rev() {
            for x in 0..self.array[y].len() {
                if let Some(tile) = self.get_tile(x, y) {
                    ...
                }
            }
        }

so i want to make a closure to make this less indented

    fn for_tile<T: Fn(&Tile, usize, usize)>(&self, function: T) {
        for y in (0..self.array.len()).rev() {
            for x in 0..self.array[y].len() {
                if let Some(tile) = self.get_tile(x, y) {
                    function(&tile, x, y);
                }
            }
        }
    }

this compiles, but i get errors when i try to use it like this:

        self.for_tile(|tile, x, y| {
            if !tile.enabled {
                self.erase_tile(*tile, x, y)
            }
        });

i get this error:

error[E0596]: cannot borrow `*self` as mutable, as it is a captured variable in a `Fn` closure
  --> src/main.rs:85:17
   |
85 |                 self.erase_tile(*tile, x, y)
   |                 ^^^^ cannot borrow as mutable

error[E0500]: closure requires unique access to `*self` but it is already borrowed
  --> src/main.rs:83:24
   |
83 |         self.for_tile(|tile, x, y| {
   |         ---- --------- ^^^^^^^^^^^^^ closure construction occurs here
   |         |    |
   |         |    first borrow later used by call
   |         borrow occurs here
84 |             if !block.enabled {
85 |                 self.erase_tile(*tile, x, y)
   |                 ---- second borrow occurs due to use of `*self` in closure
digital bobcat
#

You'll run into issues here regarding stacked mutable borrows. The surface-level error is that Fn doesn't allow you to mutate state outside the closure, so you'd need to change that to FnMut AFAICT

#

However, it'll then complain that you're borrowing self immutably while it's already borrowed mutably (or vice-versa). I'm not certain how you could fix this, besides doing ugly things with a Mutex I suppose

runic dawn
#

On a separate note, if your problem is "working with (nested) 2D vectors gets annoying", I would recommend you to write the abstraction as a type rather than function. You get some nice benefits from that, like being able to use it directly in for loops.

#

that doesn't necessarily solve your problem here, but I think it would be much nicer

#

(Or use an existing crate to do this for you)

#

to solve your particular problem, I would probably write a for_tile_mut<T: Fn(&mut Tile, ...)>(&mut self, ...), assuming that you have your self.erase_tile doesn't do much besides changing the tile

night idol
faint light
#

generally the answer here is to have fewer things that are methods on just one type

#

sometimes it makes sense to make them ordinary functions, no self

#

sometimes you can split up your types

#

but in general this is not different from how you cannot modify a vector with indexing when you are also iterating over it

#

so take the same approaches

#

for_tile_mut is a good idea especially if you separate out your tile-grid into its own type, independent of whatever other stuff is in self