Search code examples
rustrust-piston

HashMap edit value and Iter Rust


hi i have a function like that and a HashMap and the probleme is i want to iter and edit the HashMap but i have too much erro with a clone the code compil but the value of the HashMap

struct Piece(HashMap<(i32,i32), Couleur>);
fn press(&mut self, args: &Button) {
    let mut coco = self.0.clone();

    for (mut x, y) in coco {
        if let &Button::Keyboard(key) = args {
            match key {
                Key::Down => x.1 -= 1,
                Key::Left => x.0 += 1,
                Key::Right => x.0 -= 1,
                _ => {
                    println!("{:?}", x);
                }
            };
        }
    }
}

here the link of the full code if you need/want to try Link

and the dependecies of cargo

[dependencies]
piston_window = "0.93.0"
rand = "0.6.5"

Solution

  • While you're cloning self.0 to coco, the following for loop you're consuming the HashMap. So while you're modifying x you're not actually affecting the key in coco, as you cannot mutate keys in a HashMap.

    Instead wrap the body of you for loop in a map() and then collect() the result back into self.0.

    Also your +=/-= for the keys are flipped.

    fn press(&mut self, args: &Button) {
        let coco = self.0.clone();
        self.0 = coco
            .into_iter()
            .map(|(mut x, y)| {
                if let &Button::Keyboard(key) = args {
                    match key {
                        // Key::Up => x.1 -= 1,
                        Key::Down => x.1 += 1,
                        Key::Left => x.0 -= 1,
                        Key::Right => x.0 += 1,
                        _ => {
                            println!("{:?}", x);
                        }
                    };
                }
                (x, y)
            })
            .collect();
    }
    

    Alternatively, if you want to avoid cloning the whole HashMap up front, then you can use .iter() and clone() in map().

    fn press(&mut self, args: &Button) {
        self.0 = self
            .0
            .iter()
            .map(|(x, &y)| {
                let mut x = x.clone();
                if let &Button::Keyboard(key) = args {
                    match key {
                        // Key::Up => x.1 -= 1,
                        Key::Down => x.1 += 1,
                        Key::Left => x.0 -= 1,
                        Key::Right => x.0 += 1,
                        _ => {
                            println!("{:?}", x);
                        }
                    };
                }
                (x, y)
            })
            .collect::<HashMap<_, _>>();
    }
    

    or you could mem::replace() and extend().

    fn press(&mut self, args: &Button) {
        let coco = std::mem::replace(&mut self.0, HashMap::new());
        self.0.extend(coco.into_iter().map(|(mut x, y)| {
            if let &Button::Keyboard(key) = args {
                match key {
                    // Key::Up => x.1 -= 1,
                    Key::Down => x.1 += 1,
                    Key::Left => x.0 -= 1,
                    Key::Right => x.0 += 1,
                    _ => {
                        println!("{:?}", x);
                    }
                };
            }
            (x, y)
        }));
    }
    

    Also, I highly suggest using rustfmt to keep your code nicely formatted, not to mention that your mix of English and non-English names can create confusion.