Capstone: A CLI Tool
Rust is a systems programming language focused on speed, memory safety, and fearless concurrency — and a command-line tool is the perfect capstone, weaving together structs, enums, error handling, collections, and iterators into one real program.
Learn Capstone: A CLI Tool in our free Rust course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Rust course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll read command-line arguments, dispatch subcommands, model data with structs and a HashMap, and handle errors with Result — building a small task manager.
What You'll Learn in This Lesson
1️⃣ Reading Arguments and Dispatching Commands
A CLI starts by reading std::env::args() into a vector. Index 0 is the program name, so real arguments begin at index 1. You then match on the subcommand to decide what to do — exactly the enum-style dispatch you practiced earlier.
The output shown assumes you ran cargo run -- add Buy milk . The match on command.as_str() routes each subcommand to its handler — clean and extensible.
2️⃣ Modeling State and Handling Errors
Now the heart of the tool: a Task struct with a render method, a HashMap storing tasks by id, and a lookup function returning a Result so missing tasks are handled gracefully. This single program uses structs, methods, collections, Option / Result , and iterators together.
Notice ok_or turned the Option from .get into a Result with a helpful message — and because HashMap has no order, we sorted the ids before printing. Every concept from the course is pulling its weight here.
Your turn. Fill in the blanks marked ___ , then run it.
Add a pending function that returns the unfinished tasks, then list them. This is the capstone of your capstone — make it your own. Run it with cargo run .
📋 Quick Reference — CLI Tools
Practice quiz
What does std::env::args() return?
- A Vec<i32>
- A single String
- An iterator over the command-line arguments as Strings
- A HashMap of flags
Answer: An iterator over the command-line arguments as Strings. env::args() yields the arguments as an iterator of String, commonly collected into a Vec.
Which argument is the program's own name?
By convention args[0] is the program name, so real arguments start at index 1.
How do you pass arguments to your program through Cargo?
- cargo run add Buy milk
- cargo args add Buy milk
- cargo run :: add Buy milk
- cargo run -- add Buy milk
Answer: cargo run -- add Buy milk. Everything after -- is forwarded to your program, e.g. cargo run -- add Buy milk.
What does ok_or do in tasks.get(&id).ok_or(format!(...))?
- Unwraps and panics
- Converts an Option into a Result with an error value
- Sorts the map
- Removes the key
Answer: Converts an Option into a Result with an error value. ok_or turns Some(v) into Ok(v) and None into Err(message), giving a Result.
What does count_done print? // tasks: {1: true, 2: false, 3: true} // fn count_done(t) { t.values().filter(|&&d| d == true).count() } println!("done: {}", count_done(&tasks));
- done: 2
- done: 1
- done: 3
- done: 0
Answer: done: 2. Two values are true (tasks 1 and 3), so the filtered count is 2.
What does find_task print for a missing id? match find_task(&tasks, 99) { Ok(t) => println!("Found: {}", t.title), Err(e) => println!("Error: {}", e), }
- Found: 99
- It panics
- Error: no task with id 99
- Error: None
Answer: Error: no task with id 99. Id 99 is absent, so ok_or yields Err with the formatted message printed by the Err arm.
Why must you sort a HashMap's keys before printing them in order?
- HashMap reverses keys
- HashMap stores entries in no guaranteed order
- Sorting is required to read values
- HashMap keys are always strings
Answer: HashMap stores entries in no guaranteed order. A HashMap has no defined iteration order, so you collect and sort the keys for ordered output.
How do you modify a value already stored in a HashMap?
- map.get(&k)
- map.peek(&k)
- map.borrow(&k)
- map.get_mut(&k)
Answer: map.get_mut(&k). get_mut returns a mutable reference to the value (and the map must be mut).
What does rest.join(" ") do where rest is &args[2..]?
- Sums the arguments
- Joins the remaining argument strings into one space-separated String
- Sorts them
- Counts them
Answer: Joins the remaining argument strings into one space-separated String. join concatenates the slice's strings with a space between each.
Which crate is commonly used for richer command-line argument parsing?
- serde
- tokio
- clap
- rand
Answer: clap. clap handles flags, subcommands, and help text beyond simple manual parsing.