Rust Lesson Plan
A progressive curriculum to master Rust through hands-on practice.
Lesson 1: First Steps
Section titled “Lesson 1: First Steps”Goal: Run Rust and understand basic syntax.
Concepts
Section titled “Concepts”Rust is statically typed with strong safety guarantees. Cargo manages projects, dependencies, and builds.
Exercises
Section titled “Exercises”-
Create a project
Terminal window cargo new hellocd hellocargo runsrc/main.rs fn main() {println!("Hello, World!");} -
Variables and mutability
let x = 5; // Immutable// x = 6; // Error!let mut y = 5; // Mutabley = 6; // OKlet z: i32 = 10; // Explicit type -
Basic types
// Integerslet i: i32 = 42; // Signed: i8, i16, i32, i64, i128let u: u32 = 42; // Unsigned: u8, u16, u32, u64, u128// Floatslet f: f64 = 3.14; // f32, f64// Booleanlet b: bool = true;// Character (4 bytes, Unicode)let c: char = '🦀';// Stringslet s: &str = "hello"; // String slicelet s2: String = String::from("hello"); // Owned string -
Printing
let name = "Rust";println!("Hello, {}!", name);println!("Debug: {:?}", (1, 2, 3));println!("Pretty: {:#?}", vec![1, 2, 3]);
Checkpoint
Section titled “Checkpoint”Write a program that stores your name and age in variables and prints them.
Lesson 2: Control Flow
Section titled “Lesson 2: Control Flow”Goal: Use conditionals, loops, and pattern matching.
Exercises
Section titled “Exercises”-
If expressions
let x = 5;if x > 0 {println!("positive");} else if x < 0 {println!("negative");} else {println!("zero");}// If as expressionlet result = if x > 0 { "positive" } else { "non-positive" }; -
Loops
// loop (infinite)let mut count = 0;let result = loop {count += 1;if count == 10 {break count * 2; // Return value from loop}};// whilewhile count > 0 {count -= 1;}// forfor i in 0..5 { // 0, 1, 2, 3, 4println!("{}", i);}for i in 0..=5 { // 0, 1, 2, 3, 4, 5 (inclusive)println!("{}", i);}let nums = vec![1, 2, 3];for n in &nums {println!("{}", n);} -
Match expressions
let x = 5;match x {1 => println!("one"),2 | 3 => println!("two or three"),4..=10 => println!("four to ten"),_ => println!("something else"),}// Match with bindinglet point = (3, 4);match point {(0, 0) => println!("origin"),(x, 0) => println!("on x-axis at {}", x),(0, y) => println!("on y-axis at {}", y),(x, y) => println!("at ({}, {})", x, y),} -
If let
let some_value: Option<i32> = Some(42);if let Some(x) = some_value {println!("Got: {}", x);}
Checkpoint
Section titled “Checkpoint”Write a FizzBuzz program using match.
Lesson 3: Ownership
Section titled “Lesson 3: Ownership”Goal: Understand Rust’s core memory model.
Concepts
Section titled “Concepts”Each value has one owner. When the owner goes out of scope, the value is dropped. Ownership can be transferred (moved) or borrowed.
Exercises
Section titled “Exercises”-
Ownership and moves
let s1 = String::from("hello");let s2 = s1; // s1 is moved, now invalid// println!("{}", s1); // Error!println!("{}", s2); // OK// Clone for deep copylet s3 = s2.clone();println!("{} {}", s2, s3); // Both valid -
References (borrowing)
fn length(s: &String) -> usize {s.len()}let s = String::from("hello");let len = length(&s); // Borrowprintln!("{} has {} chars", s, len); // s still valid -
Mutable references
fn append(s: &mut String) {s.push_str(" world");}let mut s = String::from("hello");append(&mut s);println!("{}", s); // "hello world"// Only one mutable reference at a timelet r1 = &mut s;// let r2 = &mut s; // Error! -
Slices
let s = String::from("hello world");let hello = &s[0..5]; // "hello"let world = &s[6..]; // "world"let arr = [1, 2, 3, 4, 5];let slice = &arr[1..3]; // [2, 3]
Checkpoint
Section titled “Checkpoint”Write a function that takes a String reference and returns its first word as a slice.
Lesson 4: Structs
Section titled “Lesson 4: Structs”Goal: Define and use custom types.
Exercises
Section titled “Exercises”-
Basic structs
struct User {name: String,age: u32,active: bool,}let user = User {name: String::from("Alice"),age: 30,active: true,};println!("{} is {} years old", user.name, user.age); -
Methods
struct Rectangle {width: u32,height: u32,}impl Rectangle {// Methodfn area(&self) -> u32 {self.width * self.height}// Mutating methodfn scale(&mut self, factor: u32) {self.width *= factor;self.height *= factor;}// Associated function (constructor)fn square(size: u32) -> Rectangle {Rectangle { width: size, height: size }}}let mut rect = Rectangle::square(5);rect.scale(2);println!("Area: {}", rect.area()); -
Tuple structs
struct Point(i32, i32, i32);struct Color(u8, u8, u8);let origin = Point(0, 0, 0);let red = Color(255, 0, 0); -
Derive macros
#[derive(Debug, Clone, PartialEq)]struct Point {x: i32,y: i32,}let p1 = Point { x: 1, y: 2 };let p2 = p1.clone();println!("{:?}", p1);assert_eq!(p1, p2);
Checkpoint
Section titled “Checkpoint”Create a Circle struct with radius and methods for area and circumference.
Lesson 5: Enums and Pattern Matching
Section titled “Lesson 5: Enums and Pattern Matching”Goal: Use enums for expressive types.
Exercises
Section titled “Exercises”-
Basic enums
enum Direction {North,South,East,West,}let dir = Direction::North;match dir {Direction::North => println!("Going up"),Direction::South => println!("Going down"),_ => println!("Going sideways"),} -
Enums with data
enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(u8, u8, u8),}let msg = Message::Move { x: 10, y: 20 };match msg {Message::Quit => println!("Quit"),Message::Move { x, y } => println!("Move to {}, {}", x, y),Message::Write(text) => println!("Write: {}", text),Message::ChangeColor(r, g, b) => println!("Color: {},{},{}", r, g, b),} -
Option
fn find(items: &[i32], target: i32) -> Option<usize> {for (i, &item) in items.iter().enumerate() {if item == target {return Some(i);}}None}let nums = vec![1, 2, 3];match find(&nums, 2) {Some(i) => println!("Found at index {}", i),None => println!("Not found"),}// Combinatorsfind(&nums, 2).unwrap_or(0);find(&nums, 2).map(|i| i * 2); -
Result
use std::fs::File;use std::io::Read;fn read_file(path: &str) -> Result<String, std::io::Error> {let mut file = File::open(path)?; // ? propagates errorlet mut contents = String::new();file.read_to_string(&mut contents)?;Ok(contents)}match read_file("config.txt") {Ok(contents) => println!("{}", contents),Err(e) => eprintln!("Error: {}", e),}
Checkpoint
Section titled “Checkpoint”Create an enum for HTTP status codes with associated data for error messages.
Lesson 6: Collections
Section titled “Lesson 6: Collections”Goal: Use Vec, HashMap, and iterators.
Exercises
Section titled “Exercises”-
Vectors
let mut v: Vec<i32> = Vec::new();v.push(1);v.push(2);let v2 = vec![1, 2, 3];// Accesslet first = &v2[0]; // Panics if out of boundslet maybe = v2.get(10); // Returns Option// Iteratefor n in &v2 {println!("{}", n);}for n in &mut v {*n *= 2;} -
HashMap
use std::collections::HashMap;let mut scores: HashMap<String, i32> = HashMap::new();scores.insert(String::from("Alice"), 100);scores.insert(String::from("Bob"), 85);// Accesslet score = scores.get("Alice");// Entry APIscores.entry(String::from("Charlie")).or_insert(90);// Iteratefor (name, score) in &scores {println!("{}: {}", name, score);} -
Iterators
let nums = vec![1, 2, 3, 4, 5];// Map, filter, collectlet squares: Vec<i32> = nums.iter().map(|x| x * x).collect();let evens: Vec<i32> = nums.iter().filter(|x| *x % 2 == 0).copied().collect();// Foldlet sum: i32 = nums.iter().sum();let product: i32 = nums.iter().fold(1, |acc, x| acc * x); -
Iterator chains
let words = vec!["hello", "world", "rust"];let result: String = words.iter().map(|s| s.to_uppercase()).filter(|s| s.len() > 4).collect::<Vec<_>>().join(", ");
Checkpoint
Section titled “Checkpoint”Create a word frequency counter using HashMap and iterators.
Lesson 7: Traits
Section titled “Lesson 7: Traits”Goal: Define shared behavior.
Exercises
Section titled “Exercises”-
Define traits
trait Summary {fn summarize(&self) -> String;// Default implementationfn preview(&self) -> String {format!("Read more: {}", self.summarize())}}struct Article {title: String,content: String,}impl Summary for Article {fn summarize(&self) -> String {format!("{}", self.title)}} -
Trait bounds
// Function with trait boundfn notify<T: Summary>(item: &T) {println!("Breaking: {}", item.summarize());}// Alternative syntaxfn notify2(item: &impl Summary) {println!("Breaking: {}", item.summarize());}// Multiple boundsfn process<T: Summary + Clone>(item: T) { }// Where clausefn complex<T, U>(t: T, u: U)whereT: Summary + Clone,U: Clone + Debug,{ } -
Returning traits
fn make_summary() -> impl Summary {Article {title: String::from("News"),content: String::from("..."),}} -
Common traits
// Display - for user-facing outputuse std::fmt;impl fmt::Display for Article {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "{}", self.title)}}// From/Into - for conversionsimpl From<&str> for Article {fn from(s: &str) -> Self {Article {title: s.to_string(),content: String::new(),}}}
Checkpoint
Section titled “Checkpoint”Define a Drawable trait and implement it for Circle and Rectangle.
Lesson 8: Lifetimes and Error Handling
Section titled “Lesson 8: Lifetimes and Error Handling”Goal: Understand lifetimes and handle errors idiomatically.
Exercises
Section titled “Exercises”-
Lifetime annotations
// Return reference must live as long as inputfn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y }}// Struct with referencesstruct Excerpt<'a> {part: &'a str,} -
Static lifetime
let s: &'static str = "I live forever";// String literals are always 'static -
Custom error types
use std::error::Error;use std::fmt;#[derive(Debug)]struct ParseError {message: String,}impl fmt::Display for ParseError {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {write!(f, "Parse error: {}", self.message)}}impl Error for ParseError {} -
Error handling patterns
use anyhow::{Result, Context}; // Popular cratefn read_config() -> Result<Config> {let content = std::fs::read_to_string("config.toml").context("Failed to read config file")?;let config: Config = toml::from_str(&content).context("Failed to parse config")?;Ok(config)}
Checkpoint
Section titled “Checkpoint”Write a function that reads a file, parses JSON, and returns a custom error type on failure.
Practice Projects
Section titled “Practice Projects”Project 1: CLI Tool
Section titled “Project 1: CLI Tool”Build a command-line grep:
- Use clap for argument parsing
- Read files, search patterns
- Handle errors with anyhow
Project 2: Data Parser
Section titled “Project 2: Data Parser”Parse a custom file format:
- Define structs for data
- Implement FromStr trait
- Use iterators for processing
Project 3: HTTP Client
Section titled “Project 3: HTTP Client”Build a simple HTTP client:
- Use reqwest crate
- Async/await
- JSON deserialization with serde
Quick Reference
Section titled “Quick Reference”| Stage | Topics |
|---|---|
| Beginner | Types, control flow, ownership, borrowing |
| Intermediate | Structs, enums, traits, error handling |
| Advanced | Lifetimes, generics, async, unsafe |
See Also
Section titled “See Also”- Rust Cheatsheet — Quick syntax reference
- Testing — Cargo test patterns
- Concurrency