Question
I am trying to update a value inside a mutable HashMap, but direct indexing does not work.
use std::collections::HashMap;
fn main() {
let mut my_map = HashMap::new();
my_map.insert("a", 1);
my_map.insert("b", 3);
my_map["a"] += 10;
// I expect my_map to become {"a": 11, "b": 3}
}
However, Rust reports an error saying that the indexed content cannot be assigned to, even though the HashMap itself is mutable.
By comparison, this works with a vector:
fn main() {
let mut my_vec = vec![1, 2, 3];
my_vec[0] += 10;
println!("{:?}", my_vec);
// [11, 2, 3]
}
Why is HashMap different from Vec here, and what is the correct way to update a value in a Rust HashMap?
Short Answer
By the end of this page, you will understand why HashMap indexing in Rust can read values but not modify them, and how to update map values correctly using get_mut, insert, and the entry API. You will also see how this differs from Vec indexing and which approach to use in real code.
Concept
In Rust, a value being declared with mut does not mean every way of accessing it allows mutation. It only means you are allowed to mutate it through APIs that provide mutable access.
With Vec, indexing like my_vec[0] can return a mutable reference when used in a mutable context, because vectors support mutable indexing.
With HashMap, indexing works differently:
let value = my_map["a"];
This is designed for convenient read access. Internally, HashMap implements indexing in a way that gives you an immutable reference to the value. It does not implement mutable indexing for [], so this fails:
my_map["a"] += 10;
The reason is partly API design and safety. A hash map lookup is not the same as array indexing:
- a vector index is a direct position
- a hash map lookup depends on hashing and key lookup
- a key might not exist
- mutable indexing with
[]would need different behavior and error expectations
So, to update a value in a HashMap, Rust expects you to use methods that clearly express your intent:
Mental Model
Think of a Vec like a row of numbered lockers. If you know locker 0, you can open it directly and change what is inside.
A HashMap is more like a reception desk with labeled envelopes. Asking for "a" through indexing is like saying, "Show me the envelope for a." Rust allows that as a read-only lookup.
If you want to change the contents, you need to ask for editable access using the proper process:
get_mut()= "Give me the envelope foraso I can edit it."insert()= "Replace the envelope forawith this new one."entry()= "If the envelope exists, update it; otherwise create it."
So mut on the map means "this map may be changed," not "every access path is automatically writable."
Syntax and Examples
The most common ways to update a HashMap value are below.
1. Update an existing value with get_mut
use std::collections::HashMap;
fn main() {
let mut my_map = HashMap::new();
my_map.insert("a", 1);
my_map.insert("b", 3);
if let Some(value) = my_map.get_mut("a") {
*value += 10;
}
println!("{:?}", my_map);
}
Why this works
get_mut("a")returnsOption<&mut i32>Some(value)means the key existsvalueis a mutable reference, so you must dereference it with*value
2. Replace a value with
Step by Step Execution
Consider this example:
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("alice", 5);
if let Some(score) = scores.get_mut("alice") {
*score += 2;
}
println!("{:?}", scores);
}
Step by step
1. Create the map
let mut scores = HashMap::new();
An empty mutable HashMap is created.
2. Insert a key-value pair
scores.insert("alice", 5);
Now the map contains:
{: }
Real World Use Cases
HashMap updates are very common in practical Rust programs.
Counting occurrences
use std::collections::HashMap;
fn main() {
let words = vec!["cat", "dog", "cat", "bird", "dog", "cat"];
let mut counts = HashMap::new();
for word in words {
*counts.entry(word).or_insert(0) += 1;
}
println!("{:?}", counts);
}
Used for:
- word frequency analysis
- log event counting
- API request statistics
Updating cached values
A map may store previously computed results. When new data arrives, you update the stored value.
Tracking user scores or balances
use std::collections::HashMap;
fn () {
= HashMap::();
balances.(, );
(balance) = balances.() {
*balance -= ;
}
}
Real Codebase Usage
In real projects, developers usually avoid direct map indexing for updates and prefer clearer patterns.
Pattern: update if present
if let Some(value) = map.get_mut(key) {
*value += 1;
}
Use this when the key should already exist.
Pattern: insert default then update
*map.entry(key).or_insert(0) += 1;
This is the standard pattern for counters.
Pattern: replace a computed value
map.insert(key, new_value);
Useful when you already know the full replacement value.
Pattern: guard clause for missing data
let Some(value) = map.get_mut(key) else {
return;
};
*value += 1;
This keeps code flat and readable.
Pattern: validation before mutation
Common Mistakes
1. Assuming mut makes every access mutable
This does not work:
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
map["a"] += 1; // error
}
mut allows the map to be changed, but you still need a method that gives mutable access.
2. Forgetting to dereference get_mut() results
Broken code:
if let Some(value) = map.get_mut("a") {
value += 1;
}
Why it fails:
valueis&mut i32- you need to modify the value behind the reference
Correct code:
Comparisons
| Operation | Vec | HashMap |
|---|---|---|
| Access style | by numeric index | by key |
| Example read | vec[0] | map["a"] |
Mutable indexing with [] | Yes | No |
| Safe mutable access alternative | vec.get_mut(0) | map.get_mut("a") |
| Insert if missing | not applicable | entry(...).or_insert(...) |
get_mut vs vs
Cheat Sheet
Quick reference
Read a value by key
let v = my_map["a"];
- good for reading
- panics if the key does not exist
- does not allow mutation
Mutate an existing value
if let Some(v) = my_map.get_mut("a") {
*v += 1;
}
Replace a value
my_map.insert("a", 10);
Insert if missing, then update
*my_map.entry("a").or_insert(0) += 1;
Important rules
let mut mapmeans the map may be changed.- It does not mean
map[key]becomes writable.
FAQ
Why can't I write my_map["a"] += 1 in Rust?
Because HashMap indexing provides read-only access for []. HashMap does not implement mutable indexing, so you must use get_mut() or entry().
Does let mut my_map mean the values are mutable too?
It means the map can be modified, but only through APIs that allow mutation. Mutability depends on how you access the data.
What should I use to increment a value in a HashMap?
Use get_mut() if the key already exists, or entry().or_insert(...) if the key may be missing.
Is insert() the same as updating a value?
It can be. If the key already exists, insert() replaces the old value with the new one.
Why does vector indexing allow mutation but HashMap indexing does not?
Vec supports mutable indexing because positions are direct and predictable. HashMap uses key lookup and has a different API design, so mutation is done through methods instead.
Mini Project
Description
Build a small Rust program that counts how many times each word appears in a sentence. This demonstrates the most practical HashMap update pattern: inserting a default value when a key is missing and then mutating the existing value.
Goal
Create a word frequency counter using a HashMap and update values safely with the entry API.
Requirements
[ "Split a sentence into words.", "Store word counts in a HashMap.", "Increment the count for each word.", "Print the final map of word frequencies." ]
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Can a Struct Extend Another Struct in Rust? Composition vs Inheritance
Learn how Rust handles struct reuse without inheritance, using composition, traits, and wrapper structs with practical examples.