Welcome to Day 14! Today, I explored the final primary collection in Rust—Hash Maps—along with a sneak peek into Rust’s approach to error handling. Let’s walk through everything I learned.
🗃️ HashMaps: Key-Value Storage
Rust’s HashMap lets you store data as key-value pairs using a hashing function. It’s great when you need lookup access via keys instead of indices.
Other names in different languages: dictionary, object, map, associative array.
✅ Creating a HashMap
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
- We import HashMap from std::collections.
- Insert elements using insert(key, value).
- All keys must be of the same type, and all values must be of the same type.
🔍 Accessing Values
let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);
get returns an Option<&V>.
Use .copied().unwrap_or(0) to convert to actual value or provide a fallback.
🔁 Iterating Over a HashMap
for (key, value) in &scores {
println!("{key}: {value}");
}
- Iterates in arbitrary order.
- Keys and values are destructured in the loop.
🛠️ Ownership Rules in HashMaps
let key = String::from("Color");
let value = String::from("Blue");
let mut map = HashMap::new();
map.insert(key, value);
// key and value are now moved!
- If types like String (non-Copy) are inserted, they are moved.
- If references are inserted, ensure they outlive the HashMap.
🔁 Updating a HashMap
Rust offers multiple update strategies:
🔄 Overwrite Existing Value
scores.insert(String::from("Blue"), 25);
- Overwrites previous value.
✨ Insert If Absent – entry().or_insert()
scores.entry(String::from("Yellow")).or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
- If the key exists, it does nothing.
- If the key is missing, inserts the value.
Result:
{"Yellow": 50, "Blue": 10}
📊 Count Word Occurrences
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
*count += 1;
}
println!("{map:?}");
Result:
{"world": 2, "hello": 1, "wonderful": 1}
- entry provides a mutable reference.
- You must dereference (*count) to update.
🔐 Hashing and Security
- Rust uses SipHash by default to defend against DoS attacks.
- If performance is critical, switch to a custom hasher (implementing BuildHasher).
🧨 Sneak Peek into Error Handling
Rust separates recoverable and unrecoverable errors.
❌ Unrecoverable Errors — panic!
Used when the program hits a bug and cannot continue.
panic!("Something went wrong!");
✔️ Recoverable Errors — Result
Used when errors can be handled gracefully (e.g., missing file).
fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
Rust forces you to deal with errors explicitly—either handle or propagate them. This leads to more robust and predictable code.
📌 Summary
✔️ Things we have covered here:
- Creating and using HashMap
- Ownership rules
- Accessing and iterating
- Updating with insert, entry().or_insert()
- Word frequency counting
- Hashing and performance
- Quick intro to error handling with panic! and Result
Tomorrow, we’ll dive deeper into error handling!
Stay tuned for Day 15 tomorrow! 🦀
Happy Rusting!
Top comments (0)