09 / 20 · Day 3
Day 3 · Concept 09

Vec, HashMap, String

Vec<T> = owned growable array. HashMap<K,V> = owned hash table. String = owned UTF-8 string; &str = borrowed slice into one. The split between owned and borrowed is the entire Rust collections API condensed.


1 · Vec — the workhorse

rust src/main.rs
fn main() {
    let mut v: Vec<i32> = Vec::new();
    v.push(1);
    v.push(2);
    v.push(3);

    // The macro is shorter
    let v2 = vec![10, 20, 30];

    // Index
    println!("first: {}", v[0]);

    // Iterate
    for x in &v { println!("{}", x); }

    // Map + collect
    let doubled: Vec<i32> = v2.iter().map(|x| x * 2).collect();
    println!("{:?}", doubled);
}

2 · HashMap

rust src/main.rs
use std::collections::HashMap;

fn main() {
    let mut m: HashMap<&str, i32> = HashMap::new();
    m.insert("alice", 30);
    m.insert("bob",   25);

    // Read with .get — returns Option<&V>
    if let Some(age) = m.get("alice") {
        println!("alice is {}", age);
    }

    // Or with the "entry" API to insert-if-absent
    *m.entry("carol").or_insert(0) += 1;
    *m.entry("carol").or_insert(0) += 1;

    for (k, v) in &m {
        println!("{}={}", k, v);
    }
}

3 · The big split: String vs &str

rust src/main.rs · owned vs borrowed
fn main() {
    let owned: String = String::from("hello");  // owned, growable
    let literal: &'static str = "world";         // borrowed (the binary owns it)

    // Both are UTF-8.
    // String can grow; &str cannot.
    let mut owned = owned;
    owned.push_str(", world");
    println!("{}", owned);

    // Pass &str when you only need to read — most common.
    fn greet(s: &str) {
        println!("hi, {}", s);
    }
    greet(&owned);
    greet(literal);
    greet("inline");  // string literal coerces
}
The rule. Function parameters should be &str when you only read; String when you take ownership. String coerces to &str via &, so the function works for both.

4 · Other collections worth knowing

  • VecDeque<T> — double-ended queue. push_back / pop_front in O(1).
  • BTreeMap<K,V> — sorted map. Slower than HashMap but ordered.
  • HashSet<T> / BTreeSet<T> — the set versions.
  • LinkedList<T> — exists. Almost never the right choice. Use Vec.
  • Box<T> — owned heap pointer. Smart pointer for "this exists, single-owned, heap".

5 · Common mistakes

  • Indexing past the end. Vec[i] panics. Use .get(i) for an Option.
  • Iterating and mutating. Can't hold a & and a &mut simultaneously. Collect indices first, then mutate.
  • Indexing strings. s[0] doesn't compile — UTF-8 bytes aren't characters. Use .chars().nth(0) or .bytes().nth(0) depending.
  • Forgetting use std::collections::HashMap;. It's not in the prelude.

6 · When it clicks

  • You take &str for read; String for own. By reflex.
  • The .entry().or_insert() idiom replaces "check then insert" everywhere.
  • You reach for iter().filter().map().collect() as a first choice over loops.
Found this useful?