HashMap::contains_key() / remove() / entry()
| Since: | Rust 1.0(2015) |
|---|
Rust's HashMap provides contains_key() to check for key existence, remove() to delete entries, and the entry().or_insert() API to insert a value only when the key is absent.
Syntax
use std::collections::HashMap;
// Check whether a key exists (returns bool).
let exists = map.contains_key("Black Flash");
// Remove a key and its value (returns Option<V>).
let removed = map.remove("Black Flash"); // Some(value) or None
// entry API: insert if the key is absent.
map.entry("key".to_string()).or_insert(0);
// entry API: update an existing value.
let count = map.entry("key".to_string()).or_insert(0);
*count += 1; // Increment the value.
Method Reference
| Method | Description |
|---|---|
| map.contains_key(&key) | Returns true if the key exists. |
| map.remove(&key) | Removes the key and returns Some(value) if it existed, or None. |
| map.remove_entry(&key) | Removes and returns the key-value pair as a tuple. |
| map.entry(key) | Returns an Entry for the key (OccupiedEntry or VacantEntry). |
| .or_insert(value) | Inserts the value if the entry is vacant, then returns a mutable reference. |
| .or_insert_with(|| ...) | Inserts the closure's return value if the entry is vacant. |
| .or_default() | Inserts the default value (Default::default()) if the entry is vacant. |
| .and_modify(|v| ...) | Modifies the value only if the entry is occupied. |
| map.retain(|k, v| ...) | Retains only entries that satisfy the predicate. |
Sample Code
sample_hashmap_contains_key_remove.rs
use std::collections::HashMap;
fn main() {
let mut map: HashMap<String, i32> = HashMap::new();
map.insert("Black Flash".to_string(), 3);
map.insert("Domain Expansion".to_string(), 5);
map.insert("Reverse Cursed Technique".to_string(), 2);
// Check for key existence with contains_key().
println!("Black Flash exists?: {}", map.contains_key("Black Flash")); // true
println!("Cursed Energy exists?: {}", map.contains_key("Cursed Energy")); // false
// Delete an entry with remove().
let removed = map.remove("Domain Expansion");
println!("removed value: {:?}", removed); // Some(5)
println!("length after removal: {}", map.len()); // 2
let none = map.remove("Cursed Energy"); // Key does not exist
println!("remove non-existent key: {:?}", none); // None
// --- entry API ---
// Count technique usage (a classic entry API use case).
let cursed_techniques = "domain_expansion reverse_technique domain_expansion black_flash reverse_technique black_flash black_flash";
let mut counts: HashMap<String, i32> = HashMap::new();
for technique in cursed_techniques.split_whitespace() {
let count = counts.entry(technique.to_string()).or_insert(0);
*count += 1; // Increment through the mutable reference.
}
println!("technique counts: {:?}", counts);
// Use or_default() for the Default trait's default value.
let mut vmap: HashMap<String, Vec<i32>> = HashMap::new();
vmap.entry("evens".to_string()).or_default().push(2);
vmap.entry("evens".to_string()).or_default().push(4);
vmap.entry("odds".to_string()).or_default().push(1);
println!("groups: {:?}", vmap);
// and_modify() changes only existing values.
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("Gojo Satoru".to_string(), 90);
scores.entry("Gojo Satoru".to_string()).and_modify(|s| *s += 10);
scores.entry("Ryomen Sukuna".to_string()).and_modify(|s| *s += 10).or_insert(0);
println!("scores: {:?}", scores); // Gojo Satoru: 100, Ryomen Sukuna: 0
// retain() keeps only entries that satisfy the condition.
let mut m: HashMap<&str, i32> = [("a", 1), ("b", 2), ("c", 3), ("d", 4)]
.iter().cloned().collect();
m.retain(|_, v| *v >= 3); // Keep only entries where value >= 3.
println!("retain(value >= 3): {:?}", m);
}
Compile with the following command:
rustc hashmap_contains_key_remove.rs
./hashmap_contains_key_remove
Black Flash exists?: true
Cursed Energy exists?: false
removed value: Some(5)
length after removal: 2
remove non-existent key: None
technique counts: {"domain_expansion": 2, "reverse_technique": 2, "black_flash": 3}
groups: {"evens": [2, 4], "odds": [1]}
scores: {"Gojo Satoru": 100, "Ryomen Sukuna": 0}
retain(value >= 3): {"c": 3, "d": 4}
Common Mistakes
Common mistake 1: borrow error when using entry() and reading the map simultaneously
Calling entry() takes a mutable borrow of the map. Trying to read the map while holding the returned mutable reference is a compile error.
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("Gojo Satoru".to_string(), 90);
// Compile error: cannot borrow `scores` as immutable while a mutable borrow is active
// let e = scores.entry("Gojo Satoru".to_string()).or_insert(0);
// println!("{}", scores.get("Gojo Satoru").unwrap()); // NG
// *e += 1;
}
The same logic can also be written as:
use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
scores.insert("Gojo Satoru".to_string(), 90);
// Correct: finish using the mutable reference before reading the map
{
let e = scores.entry("Gojo Satoru".to_string()).or_insert(0);
*e += 10;
}
println!("{}", scores["Gojo Satoru"]); // 100
}
Common mistake 2: searching twice with contains_key() then get()
Calling contains_key() followed by get() performs two lookups for the same key. Using get() directly and handling the Option is more efficient.
use std::collections::HashMap;
fn main() {
let mut map: HashMap<String, i32> = HashMap::new();
map.insert("Fushiguro Megumi".to_string(), 80);
// Inefficient: two lookups for the same key
if map.contains_key("Fushiguro Megumi") {
let val = map.get("Fushiguro Megumi").unwrap();
println!("value: {}", val);
}
}
The same logic can also be written as:
use std::collections::HashMap;
fn main() {
let mut map: HashMap<String, i32> = HashMap::new();
map.insert("Fushiguro Megumi".to_string(), 80);
// Efficient: one lookup, handle the Option directly
if let Some(val) = map.get("Fushiguro Megumi") {
println!("value: {}", val);
}
}
Overview
The entry API is one of the most idiomatic ways to use a HashMap. It lets you safely and efficiently express "insert if absent, update if present." It is commonly used for aggregation tasks like counting occurrences.
or_insert() returns a mutable reference (&mut V) to the value. Through this reference you can mutate the value, enabling operations like incrementing or appending to a vector.
HashMap has no built-in contains_value() method. To find a key that holds a specific value, use values().any(|v| v == &target) or iter().find(|(k, v)| v == &&target).
For creating and querying a HashMap, see HashMap::new() / insert() / get(). For iteration, see HashMap::keys() / values() / iter().
If you find any errors or copyright issues, please contact us.