Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return exact value in Rust HashMap

I can't find a suitable way to return the exact value of key in a HashMap in Rust . All the existing get methods return in a different format rather than the exact format.

like image 712
Rahul Choudhary Avatar asked Apr 14 '17 17:04

Rahul Choudhary


2 Answers

You probably want the HashMap::remove method - it deletes the key from the map and returns the original value rather than a reference:

use std::collections::HashMap;

struct Thing {
    content: String,
}

fn main() {
    let mut hm: HashMap<u32, Thing> = HashMap::new();
    hm.insert(
        123,
        Thing {
            content: "abc".into(),
        },
    );
    hm.insert(
        432,
        Thing {
            content: "def".into(),
        },
    );

    // Remove object from map, and take ownership of it
    let value = hm.remove(&432);

    if let Some(v) = value {
        println!("Took ownership of Thing with content {:?}", v.content);
    };
}

The get methods must return a reference to the object because the original object can only exist in one place (it is owned by the HashMap). The remove method can return the original object (i.e "take ownership") only because it removes it from its original owner.

Another solution, depending on the specific situation, may be to take the reference, call .clone() on it to make a new copy of the object (in this case it wouldn't work because Clone isn't implemented for our Thing example object - but it would work if the value way, say, a String)

Finally it may be worth noting you can still use the reference to the object in many circumstances - e.g the previous example could be done by getting a reference:

use std::collections::HashMap;

struct Thing {
    content: String,
}

fn main() {
    let mut hm: HashMap<u32, Thing> = HashMap::new();
    hm.insert(
        123,
        Thing {
            content: "abc".into(),
        },
    );
    hm.insert(
        432,
        Thing {
            content: "def".into(),
        },
    );

    let value = hm.get(&432); // Get reference to the Thing containing "def" instead of removing it from the map and taking ownership

    // Print the `content` as in previous example.
    if let Some(v) = value {
        println!("Showing content of referenced Thing: {:?}", v.content);
    }
}
like image 54
dbr Avatar answered Oct 13 '22 11:10

dbr


There are two basic methods of obtaining the value for the given key: get() and get_mut(). Use the first one if you just want to read the value, and the second one if you need to modify the value:

fn get(&self, k: &Q) -> Option<&V>
fn get_mut(&mut self, k: &Q) -> Option<&mut V>

As you can see from their signatures, both of these methods return Option rather than a direct value. The reason is that there may be no value associated to the given key:

use std::collections::HashMap;

let mut map = HashMap::new();
map.insert(1, "a");
assert_eq!(map.get(&1), Some(&"a")); // key exists
assert_eq!(map.get(&2), None);       // key does not exist

If you are sure that the map contains the given key, you can use unwrap() to get the value out of the option:

assert_eq!(map.get(&1).unwrap(), &"a");

However, in general, it is better (and safer) to consider also the case when the key might not exist. For example, you may use pattern matching:

if let Some(value) = map.get(&1) {
    assert_eq!(value, &"a");
} else {
    // There is no value associated to the given key.
}
like image 42
s3rvac Avatar answered Oct 13 '22 09:10

s3rvac