31. HashMap's entry API

Want to insert a value into a HashMap only if the key doesn’t exist yet? Skip the double lookup — use the entry API.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use std::collections::HashMap;

let mut scores: HashMap<&str, Vec<u32>> = HashMap::new();

// Instead of checking .contains_key() then inserting:
scores.entry("alice")
    .or_insert_with(Vec::new)
    .push(100);

scores.entry("alice")
    .or_insert_with(Vec::new)
    .push(200);

assert_eq!(scores["alice"], vec![100, 200]);

The entry API returns an Entry enum — either Occupied or Vacant. The convenience methods make common patterns a one-liner:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
use std::collections::HashMap;

let mut word_count: HashMap<&str, usize> = HashMap::new();
let words = ["hello", "world", "hello", "rust", "hello"];

for word in words {
    *word_count.entry(word).or_insert(0) += 1;
}

// hello => 3, world => 1, rust => 1

or_insert(val) inserts a default, or_insert_with(|| val) lazily computes it, and or_default() uses the type’s Default. All three return a mutable reference to the value, so you can update in place.

#030 Mar 2026

30. dbg! macro

Still using println! for quick debugging? Try dbg! instead — it prints the expression, its value, and the file/line number to stderr. And it returns the value, so you can wrap it around anything.

1
2
3
4
5
6
let a = 2;
let b = dbg!(a * 2) + 1; // prints: [src/main.rs:3] a * 2 = 4
assert_eq!(b, 5);

// works with multiple values too
dbg!(a, b, a + b); // prints each as a tuple

Unlike println!, dbg! takes ownership (or copies for Copy types). If you need to keep the value, pass a reference:

1
2
3
let name = String::from("Ferris");
dbg!(&name); // borrows, doesn't move
println!("{name}"); // still works!

Bonus: dbg! works the same in release builds, and outputs to stderr so it won’t pollute your stdout.

29. Let chains

Tired of deeply nested if let blocks? Rust 2024 edition brings let chains — chain multiple let patterns with && in a single if expression.

1
2
3
4
5
6
7
8
// Before: nested and hard to read
if let Some(a) = opt_a {
    if let Some(b) = opt_b {
        if a > 0 {
            println!("{a} + {b} = {}", a + b);
        }
    }
}

With let chains, flatten the whole thing:

1
2
3
4
5
6
if let Some(a) = opt_a
    && let Some(b) = opt_b
    && a > 0
{
    println!("{a} + {b} = {}", a + b);
}

Works with while too!

1
2
3
4
5
6
7
8
9
let mut iter = vec![Some(1), Some(2), None, Some(4)].into_iter();

while let Some(inner) = iter.next()
    && let Some(val) = inner
{
    println!("got: {val}");
}
// prints: got: 1, got: 2
// stops at None — the inner let fails

You can mix boolean expressions and let bindings freely. Each && can be either a regular condition or a pattern match.

Note: requires edition 2024 (edition = "2024" in Cargo.toml).

#028 Feb 2023

28. Raw string

Curious to know how you can add a double quote in raw strings?

No escape sequences are recognized in raw strings, so adding a backslash does not work.

Use ### to mark the start and the end of a raw string.

1
2
3
4
5
6
7
8
println!("This is a double quote \" ");

// println!(r"This is a double quote " "); // Nope!
// println!(r"This is a double quote \" "); // Nope!

// And this works
println!(r#"This is a double quote " "#);
println!(r###"This is a double quote " "###);
#027 Jan 2023

27. Option's sum/product

Rust’s option implements Sum and Product traits too!

Use it when you want to get None if there is a None element and sum of values otherwise.

1
2
3
let nums: [Option<u32>;3] = [Some(1), Some(10), None];
let maybe_nums: Option<u32> = nums.into_iter().sum();
assert_eq!(maybe_nums, None);

or sum of the values …

1
2
3
let nums = [Some(1), Some(10), Some(100)];
let maybe_nums: Option<u32> = nums.into_iter().sum();
assert_eq!(maybe_nums, Some(111));

And product.

1
2
3
let nums = [Some(1), Some(10), Some(100)];
let maybe_nums: Option<u32> = nums.into_iter().product();
assert_eq!(maybe_nums, Some(1000));
#026 Jan 2023

26. Collecting into Option

Rust’s option implements FromIterator too!

Use it when you want to get None if there is a None element and values otherwise.

1
2
3
let cars = [Some("Porsche"), Some("Ferrari"), None];
let maybe_cars: Option<Vec<_>> = cars.into_iter().collect();
assert_eq!(maybe_cars, None);

or values …

1
2
3
let cars = [Some("Porsche"), Some("Ferrari"), Some("Skoda")];
let maybe_cars: Option<Vec<_>> = cars.into_iter().collect();
assert_eq!(maybe_cars, Some(vec!["Porsche", "Ferrari", "Skoda"]));
#025 Dec 2022

25. Option's iterator

Rust’s option implements an iterator!

1
2
3
4
let o: Option<u32> = Some(200u32);
let mut iter = o.into_iter();
let v = iter.next();
assert_eq!(v, Some(200u32));

Why is this useful? see example.

1
2
3
4
5
6
let include_this_pls = Some(300u32);
let r: Vec<u32> = (0..2).chain(include_this_pls).chain(2..5).collect();
assert_eq!(r, vec![0,1,300,2, 3,4]);
let but_not_this = None;
let r: Vec<u32> = (0..2).chain(but_not_this).chain(2..5).collect();
assert_eq!(r, vec![0,1,2,3,4]);
#024 Dec 2022

24. ..=X

As of 1.66, it is possible to use ..=X in patterns

1
2
3
4
5
6
let result = 20u32;

match result {
    0..=20 => println!("Included"),
    21.. => println!("Sorry"),
}
#023 Dec 2022

23. Enum's default value

Instead of manually implementing Default trait for an enum, you can derive it and explicitly tell which variant should be the default one.

1
2
3
4
5
6
7
8
9
#[derive(Default)]
enum Car{
    #[default]
    Porsche,
    Ferrari,
    Skoda
}

let car = Car::default();
#022 Nov 2022

22. Enum's Debug

Use Debug trait to print enum values if needed.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#[derive(Default,Debug)]
enum Car{
    #[default]
    Porsche,
    Ferrari,
    Skoda
}

let car = Car::default();
println!("{:?}", car);