Mapping and modifying objects within a HashMap

Hi there,

I need some help here. What I am trying to do is to mapp some objects and modify them if a new value is presented. In the test case below i have a mock-up of what i am trying to achieve.

Let say i iterate through a vec of keys for each key i want to check if it exists in my hashmap and if it does not i want to create a new object X with a key value set and another value (vals[i]) pushed to it. On the other hand if it already exists i would like to just push the value (vals[i]).

use std::collections::HashMap;
#[derive(Debug)]
struct X {
    r: String,
    v: Vec<u8>,
}

impl X {
    pub fn new() -> Self {
        X {
            r: "x".to_string(),
            v: Vec::new(),
        }
    }
    fn add(&mut self, x: u8) -> &mut Self {
        self.v.push(x);
        self
    }
    fn set(&mut self, x: &str) -> &mut Self {
        self.r = x.to_string();
        self
    }
}

fn main() {
    let vals  = vec![5u8; 4];
    let keys = vec!["X".to_string(), "X".to_string(), "Y".to_string(), "Y".to_string()];

    let mut res: HashMap<String, &mut X> = HashMap::default();
    let mut i = 0;

    while i < vals.len() {
        res.entry(keys[i].clone())
            .and_modify(|x| {
                x.add(vals[i] + 1u8);
            })
            .or_insert(X::new().set(&keys[i]).add(vals[i]));
        i += 1;
    }

    println!("{:#?}", res)
}

if i execute it i get

   Compiling playground v0.0.1 (/playground)
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:37:24
   |
33 |         res.entry(keys[i].clone())
   |         --- borrow later used here
...
37 |             .or_insert(X::new().set(&keys[i]).add(vals[i]));
   |                        ^^^^^^^^                            - temporary value is freed at the end of this statement
   |                        |
   |                        creates a temporary value which is freed while still in use
   |
   = note: consider using a `let` binding to create a longer lived value

For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground` (bin "playground") due to 1 previous error

I understand what compiler is complaining about but i do not know how to fix it :frowning:

Can someone maybe provide some help here ?

Thank you

You've created a new X but it has no owner because you're only storing a reference &mut X in the HashMap. Are you sure you don't want to store X itself in the HashMap?

but how do i modify it then afterwords if it is not mutable? (sorry, now we are exposing my lack of understanding of rust in general)

Owned values are mutable, and your hashmap res is mutable, so you can modify its entries. The and_modify method gives your closure a mutable reference to the entry.

Also, you probably should use or_insert_with instead of or_insert, so that you don't create a new X in the case where an entry already exists. With or_insert_with, your closure will only be called to create a new X when one is needed.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.