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.