Step 4: The Rust version
Rust looks like C++ here but adds guarantees. A HashMap counts words with the entry API (*counts.entry(word).or_insert(0) += 1), split with a closure breaks the text, and sort_by with .then() sorts by count then name. The function returns a Vec<(String, usize)> which the caller owns.
use std::collections::HashMap;
fn count_words(text: &str) -> Vec<(String, usize)> {
let mut counts: HashMap<String, usize> = HashMap::new();
for word in text
.to_lowercase()
.split(|c: char| !c.is_alphabetic())
.filter(|w| !w.is_empty())
{
*counts.entry(word.to_string()).or_insert(0) += 1;
}
let mut sorted: Vec<(String, usize)> = counts.into_iter().collect();
sorted.sort_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(&b.0)));
sorted
}
fn main() {
let text = "The quick brown fox jumps over the lazy dog. The end!";
for (word, count) in count_words(text) {
println!("{:<6} {}", word, count);
}
}the 3 brown 1 dog 1 end 1 fox 1 jumps 1 lazy 1 over 1 quick 1
The compiler proved that no reference outlives its data and that nothing is used after being moved, so there are no hidden memory bugs, and there is no garbage collector either. The price is learning the ownership rules; the reward is safety with C-like speed.
What does the entry API do in the Rust version?
Finish the quick check (and any code exercise) to complete this lesson, or mark it done yourself.
Tip: use the left and right arrow keys to move between lessons.