Rust from Basics to Mastery — Part 6
Processing data with collections, iterators, and closures
The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.
Rust's standard collections own the values they store. Iterators differentiate by type the way a collection is read, borrowed, or consumed.
Vec and HashMap
use std::collections::HashMap;
let mut party = Vec::new();
party.push(String::from("Rose"));
let mut items = HashMap::new();
items.insert(10, String::from("Potion"));
if let Some(name) = items.get(&10) {
println!("{name}");
}
Vec is an ordered list and HashMap finds values by key. Because get may not have a value, it returns Option.
The borrow checker prevents internal element references from being retained while the collection is reallocated or modified.
Ownership method of iterator
for name in &party {
println!("{name}");
}
for name in &mut party {
name.push_str("_01");
}
&party borrows the element immutably, and &mut party borrows it mutable. If party itself is repeated as a value, the ownership of the element moves and the original cannot be used later.
Iterators and Closures
let mut alive: Vec<&Monster> = monsters
.iter()
.filter(|monster| monster.health > 0)
.collect();
alive.sort_by_key(|monster| monster.health);
iter creates an iterator that borrows elements, and filter passes only values that meet the conditions. The final collection is created when collect is called.
let bonus = 5;
let add_bonus = |damage: i32| damage + bonus;
Closures can be captured by borrowing or moving surrounding values. If the closure needs to outlive its original scope, you need to check whether move is needed and where the ownership goes.
Iterator code is not necessarily used because it is fast. The advantage is that the intention of filters and transformations can be expressed in stages while maintaining the ownership and borrowing methods.