#How to fix `cannot borrow `*self` as immutable because it is also borrowed as mutable`?

9 messages · Page 1 of 1 (latest)

tribal sapphire
#
pub fn get_chunk(&mut self, position: Point<i32>) -> &mut Chunk {
        return self
            .chunks
            .entry((position.x, position.y))
            .or_insert_with(|| {
                return self.generate_chunk(position);
            });
    }
cannot borrow `*self` as immutable because it is also borrowed as mutable
signal shore
#

You're not allowed to borrow self in the closure, because you already have a mutable borrow while you hold the Entry.
There's basically three fixes to this:

  • Generate the chunk in advance (I assume that's costly and you don't want that`
  • Split finding and inserting into two operations (i.e. don't use entry)
  • Change generate_chunk to not use (all of) self.
tribal sapphire
#

Hm, I'm don't understand how to resolve the problem using yours second suggestion.
I tried to split finding and inserting. It didn't help.

    pub fn get_chunk(&mut self, position: Point<i32>) -> &mut Chunk {
        if let Some(chunk) = self.chunks.get_mut(&(position.x, position.y)) {
            return chunk;
        }
        let chunk = self.generate_chunk(position);
        self.chunks.insert((position.x, position.y), chunk);
        return self.chunks.get_mut(&(position.x, position.y)).unwrap();
    }
#

The relocation of chunk generation from the current structure is not advisable due to the extensive architectural modifications or potential violation of SOLID principles that it would entail.

tribal sapphire
#

What a heck

    pub fn get_chunk(&mut self, position: Point<i32>) -> &mut Chunk {
        if self.chunks.contains_key(&(position.x, position.y)) {
            return self.chunks.get_mut(&(position.x, position.y)).unwrap();
        }

        let chunk = self.generate_chunk(position);
        self.chunks.insert((position.x, position.y), chunk);
        return self.chunks.get_mut(&(position.x, position.y)).unwrap();
    }

it works
I got why it didn't work, but it's painful after other programming languages...

Especially I'm getting disappointed by this part:

let chunk = self.generate_chunk(position);
self.chunks.insert((position.x, position.y), chunk);
return self.chunks.get_mut(&(position.x, position.y)).unwrap();
latent knoll
#

You could say that it does not take self, and instead takes only the fields it needs (or perhaps is a method defined on a struct of only those fields)

#

Another option is to simply make generate_chunks actually only generate the chunk if needed. Basically, you merge get_chunk and generate_chunk. Then you rename the function to get_or_generate_chunk

#

That is:

pub fn get_chunk(&mut self, position: Point<i32>) -> &mut Chunk {
  self //those returns were both unnecessary, btw
    .chunks
    .entry((position.x, position.y))
    .or_insert_with(|| {
      Self::generate_chunk(position, self.other_field_this_function_needs);
    });
}