Collections
Vec
Vec<T> is a growable, heap-allocated array. Like List<T> in C#.
let mut v: Vec<i32> = Vec::new();
v.push(1);
v.push(2);
v.push(3);
let v2 = vec![10, 20, 30]; // macro for initial values
println!("{:?}", v);In C#: Like var v = new List<int>(); v.Add(1); or new List<int> { 10, 20, 30 }. Ownership: the Vec owns its elements; when the Vec is dropped, elements are dropped.
HashMap
HashMap<K, V> stores key-value pairs. Like Dictionary<K, V> in C#.
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("a", 1);
map.insert("b", 2);
println!("{:?}", map.get("a")); // Some(1)In C#: Like var map = new Dictionary<string, int>();. insert(k, v) moves both the key and the value into the map (no copy unless the types are Copy) and returns Option<V>: the previous value for that key, or None if the key was new.
let mut scores = HashMap::new();
let prev = scores.insert("alice", 10); // None -> key was new
let prev2 = scores.insert("alice", 20); // Some(10) -> previous value returnedIn C#: Roughly like indexer assignment map["alice"] = 10;, except the C# indexer returns nothing. Note that the C# write syntax does not work in Rust: map["a"] = 1; does not compile. HashMap implements Index (so you can read with map["a"], which panics on a missing key) but it deliberately does not implement IndexMut, so there is no map["a"] = ... write form. Use map.insert("a", 1) instead.
Updating in place: entry().or_insert()
A very common need is "look up a key, and if it is absent install a default, then update it". The idiomatic way is entry(key).or_insert(default), which returns a mutable reference (&mut V) to either the existing value or the freshly inserted default:
use std::collections::HashMap;
let text = "the quick brown fox the lazy dog the";
let mut counts: HashMap<&str, i32> = HashMap::new();
for word in text.split_whitespace() {
*counts.entry(word).or_insert(0) += 1; // upsert + increment
}
println!("{:?}", counts.get("the")); // Some(3)The * dereferences the &mut i32 so you can add to the value behind it. This is a single hash lookup, not two.
In C#: Equivalent to counts[word] = counts.GetValueOrDefault(word, 0) + 1;, or the older if (!counts.TryGetValue(word, out var c)) c = 0; counts[word] = c + 1;. The Rust entry API folds the lookup, the default, and the update into one operation. For more elaborate cases use or_insert_with(|| ...) (lazy default) or and_modify(|v| ...).or_insert(...).
HashSet
HashSet<T> is an unordered set of unique values. Like HashSet<T> in C#.
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(1); // no duplicate
println!("{:?}", set); // {1, 2} (order not guaranteed)In C#: Same idea as HashSet<T>.
Iteration
for x in &v {
println!("{}", x);
}
for (k, v) in &map {
println!("{}: {}", k, v);
}In C#: Like foreach (var x in list) and foreach (var kv in dict). In Rust, iterating by reference (&v, &map) does not consume the collection.
Common pitfalls
Indexing with v[i] or map[k] panics if the index is out of range or the key is missing — it aborts the program (like an unhandled exception) rather than returning a sentinel:
let v = vec![10, 20, 30];
// let bad = v[99]; // PANIC: index out of bounds
match v.get(99) {
Some(n) => println!("got {}", n),
None => println!("out of range"), // this branch runs
}Prefer .get(), which returns an Option: Some(&value) if present, None if not. The same applies to HashMap:
use std::collections::HashMap;
let prices: HashMap<&str, i32> = HashMap::new();
if let Some(p) = prices.get("missing") {
println!("price {}", p);
} else {
println!("no such key"); // this branch runs
}In C#: map[key] on a missing key throws KeyNotFoundException and list[i] out of range throws ArgumentOutOfRangeException. Rust's .get() is the analog of Dictionary.TryGetValue — a checked lookup that tells you whether the entry exists instead of throwing. Reach for [] only when you are certain the element is present and want a panic if your assumption is wrong.
Key takeaway
Use Vec<T>, HashMap<K, V>, and HashSet<T> for dynamic collections. They own their elements. Iterate with for x in &collection to avoid moving. Update maps with entry(k).or_insert(default), write with insert (not map[k] = v), and read safely with .get() (returns Option) instead of [], which panics on a missing key or out-of-range index.