← Rust Programming For Systems · Lesson 1 of 5

Course Outline

📖 Every lesson in this course is free to read right here, no account needed. Create a free account to track your progress, take the exam, and earn your certificate.
1

Course Outline

Rust Programming for Systems – Course Outline

Rust Programming for Systems

Course Outline

A beginner-friendly course for curious young minds

This course teaches you how to write safe and fast programs using the Rust programming language. You will learn step by step, with lots of examples, stories, and fun activities.


Module One: Welcome to Rust

Your first steps into systems programming.

  • What is systems programming?
  • Why Rust is special: safety, speed, and concurrency
  • Installing Rust and Cargo
  • Your first program: Hello, World!
  • Variables and data types
  • Mutability: change or not to change
  • Functions and comments
  • The Rust compiler and Cargo
  • Printing and reading input

Module Two: Making Decisions and Repeating Actions

Control flow in Rust.

  • Making decisions with if, else if, and else
  • Boolean logic: &&, ||, and !
  • Pattern matching with match
  • Loops: loop, while, and for
  • Expressions vs statements
  • Introduction to ownership and borrowing
  • Common mistakes and best practices

Module Three: Building Your Own Types

Structs, enums, and error handling.

  • Grouping data with structs
  • Adding methods with impl
  • Representing choices with enums
  • Enums with data
  • Pattern matching with enums
  • Handling missing values with Option
  • Handling errors with Result
  • Using unwrap, expect, and the ? operator
  • Deriving traits like Debug

Module Four: Working with Collections and Generics

Storing many values and writing flexible code.

  • Vectors: lists of values
  • Strings and text handling
  • Hash maps: key-value storage
  • Iterators and closures
  • Generics: writing code for many types
  • Traits: shared behaviour
  • Modules and project organisation
  • Testing and debugging
  • Building a complete project

What You Will Build

Module Mini Project
Module One My Daily Routine program
Module Two Guess the Number game
Module Three Student Report Card program
Module Four Contact List or To-Do List app

Who Is This Course For?

  • Beginners with no coding experience
  • Young learners aged 10 and above
  • Anyone curious about how computers work
  • Future systems programmers

What You Need

  • A computer (Windows, Mac, or Linux)
  • Internet connection to install Rust
  • A text editor or code editor
  • Curiosity and patience

How You Will Learn

  • Short, simple lessons
  • Fun stories and examples
  • Nigerian and everyday examples
  • Step-by-step explanations
  • Hands-on activities and projects
  • Quizzes and matching exercises

Start your journey today. Learn Rust, build safe programs, and become a systems programmer!

2

Module One

Rust Programming for Systems – Module One

Module One: Welcome to Rust – Your First Steps into Systems Programming

“Rust Programming for Systems” – A beginner’s course for curious minds

Module Introduction

Hello, young coder! Have you ever wondered how computers talk to each other? How do they store your games, keep your messages safe, and run your favourite apps without crashing? The answer lies in systems programming. And the best language to learn systems programming today is Rust.

Rust is a language that helps you build fast, safe, and reliable programs. It is used by big companies like Microsoft, Google, and Amazon. But don’t worry—it is also fun and friendly for beginners. In this module, we will start from the very beginning. We will learn what Rust is, why it is special, and how to write your very first Rust programs. No prior coding experience needed. Just bring your curiosity!

We will use simple words, lots of stories, and examples from Nigeria and around the world. By the end, you will understand the heart of Rust and be ready to write your own small programs.

Learning Objectives

After finishing this module, you will be able to:

  • Explain what Rust is and why it is used for systems programming.
  • Describe the main features that make Rust special (safety, speed, and concurrency).
  • Install Rust on your computer and run a simple program.
  • Write and understand basic Rust code using variables, data types, and simple output.
  • Use comments to explain your code.
  • Recognize common mistakes and best practices.
  • Connect Rust ideas to real-life examples from Nigeria and everyday life.
  • Complete a mini project and practical assignment.

Warm-up Story: Ada and the Broken Robot

Once upon a time in Lagos, Nigeria, there lived a clever girl named Ada. Ada loved building things. One day, she built a small robot named Chidi. Chidi could walk, talk, and even fetch water. But there was a problem: Chidi kept crashing into walls! Every time Ada gave Chidi a command, Chidi would get confused and fall down.

Ada asked her friend, Tunde, who was a computer whiz. Tunde said, “Ada, the problem is not Chidi’s body. It is Chidi’s brain. The instructions inside Chidi are not safe. The computer language you used lets Chidi make mistakes that the computer cannot catch. You need a language that checks your work before the robot moves.”

Ada was curious. “Which language can do that?” she asked. Tunde smiled and said, “Rust! Rust is like a careful teacher. It checks every instruction before the robot runs. It stops mistakes that could make Chidi crash. With Rust, Chidi can walk safely and never bump into walls again.”

Ada decided to learn Rust. And that is exactly what we are going to do today. Just like Ada, we will learn how Rust helps us build safe and strong programs—without crashing!

Moral of the story: Rust helps you write code that is safe and correct, so your programs (or robots!) don’t break easily.

Main Lessons

Lesson 1: What is Systems Programming?

Definition: Systems programming is writing software that controls the computer’s hardware and makes other programs run. It is like being the engineer who builds the roads and bridges that other cars (apps) drive on.

Why it is important: Without systems programming, your computer would not know how to turn on, save files, or connect to the internet.

Simple explanation: Imagine your computer is a big city. Systems programs are the roads, traffic lights, and water pipes. They keep everything moving. Apps like games and browsers are the cars and houses that use those roads.

Real-life example: The operating system (like Windows, macOS, or Linux) is a systems program. It manages your keyboard, screen, and memory.

School example: The school timetable is like a systems program. It tells each class when to go to which room. Without it, chaos!

Home example: Your home’s electrical wiring is a system. It delivers power to your TV, fridge, and lights safely.

Nigerian example: The traffic lights in Abuja are systems. They control when cars move and stop. If they fail, there is a big hold-up. Systems programming keeps such systems working.

Illustration:

  +-------------------+       +-------------------+
  |   HARDWARE        |       |   SYSTEMS         |
  | (CPU, memory,     |<----->|   PROGRAM         |
  |  disk, screen)    |       | (Operating System)|
  +-------------------+       +-------------------+
          ^                            ^
          |                            |
          |                            |
  +-------------------+       +-------------------+
  |   APPLICATIONS    |       |   RUST CODE       |
  | (Games, browsers) |       | (You write this!) |
  +-------------------+       +-------------------+
  

Mini summary: Systems programming builds the foundation that all other software uses. Rust is a language made for this job.

Lesson 2: Why Rust? The Superpowers of Rust

Definition: Rust is a programming language that focuses on speed, safety, and doing many things at once (concurrency).

Why it is important: Many programs crash because of memory errors. Rust stops those errors before the program even runs.

Simple explanation: Think of Rust as a strict but caring coach. It checks your code and says, “Wait, this part might cause a problem. Let’s fix it now.” Other languages might let you run and then crash later.

Real-life example: A bank uses Rust to handle millions of transactions. If the program crashes, people lose money. Rust prevents crashes.

School example: A teacher who marks your homework before you submit it is like Rust. A teacher who only marks after you fail is like some other languages.

Home example: Before you cook, your mum checks if the gas is off. Rust checks your code before it runs.

Nigerian example: In a busy market like Balogun in Lagos, a good trader counts money carefully before giving change. Rust counts and checks memory carefully to avoid “change” errors.

Illustration:

  Other languages:        Rust:
  Write code              Write code
       |                       |
       V                       V
  Run program             Compiler checks
       |                       |
       V                       V
  Maybe crash!            If safe, run
                          Else, fix first
  

Mini summary: Rust is safe, fast, and prevents many common bugs. That is why big companies love it.

Lesson 3: Installing Rust – Your Toolkit

Definition: Installing Rust means putting the Rust tools on your computer so you can write and run Rust programs.

Why it is important: You cannot build a house without tools. Rust has its own tools: rustc (the compiler) and cargo (the project manager).

Simple explanation: rustc turns your human-readable code into computer instructions. cargo helps you create projects, add libraries, and run tests.

Real-life example: A carpenter uses a hammer and saw. A Rust programmer uses rustc and cargo.

School example: Your school bag holds your books and pens. Cargo is like your school bag for Rust projects.

Home example: A toolbox in your house has a screwdriver and pliers. The Rust installation gives you a toolbox for coding.

Nigerian example: A tailor in Kano uses a sewing machine and scissors. A Rust programmer uses rustc and cargo to “stitch” code together.

Illustration:

  Your Computer
       |
       V
  Install Rust (from rustup.rs)
       |
       +--> rustc (compiler)
       |
       +--> cargo (project manager)
       |
       V
  Ready to write Rust!
  

Mini summary: Install Rust using rustup. Then you get rustc and cargo to build programs.

Lesson 4: Your First Rust Program – Hello, World!

Definition: A “Hello, World!” program is the simplest program that prints a message to the screen.

Why it is important: It confirms that your tools work and you can run Rust code.

Simple explanation: You write a few lines. The computer reads them and shows “Hello, World!” on your screen.

Real-life example: When you say “Hello” to a friend, they say “Hello” back. Here, you tell the computer to say “Hello, World!”.

School example: The first day of school, you introduce yourself. This is your program’s introduction.

Home example: When you knock on a door, someone answers. This program knocks on the computer’s door.

Nigerian example: In Nigeria, we greet with “How are you?” The computer greets with “Hello, World!”.

Illustration:

  fn main() {
      println!("Hello, World!");
  }
  

Step-by-step explanation:

  • fn main() { ... } – This is the starting point. Every Rust program begins here.
  • println!("Hello, World!"); – This prints the text inside the quotes.
  • The semicolon ; tells Rust that the instruction is finished.

Mini summary: “Hello, World!” is your first step. It shows you how to write and run a basic Rust program.

Lesson 5: Variables – Boxes for Keeping Things

Definition: A variable is a named box that stores a value. You can change what is inside (unless it is immutable).

Why it is important: Programs need to remember numbers, words, and other data. Variables hold that data.

Simple explanation: Imagine a kitchen cupboard. You put rice in one container, beans in another. You label them “rice” and “beans”. In Rust, you write let rice = 5;.

Real-life example: Your school bag has pockets for books, pens, and lunch. Each pocket is a variable.

School example: A register has columns for names, ages, and scores. Each column is like a variable.

Home example: Your phone’s contact list stores names and numbers. Each contact is a variable.

Nigerian example: A trader in Onitsha market has baskets for tomatoes, peppers, and onions. Each basket is a variable.

Illustration:

  let age = 13;
  let name = "Ada";
  let is_hungry = true;
  

Mini summary: Variables store data. Use let to create them. You can change them later if you use mut.

Lesson 6: Data Types – Different Kinds of Boxes

Definition: A data type tells Rust what kind of value a variable holds: a number, a word, a true/false, etc.

Why it is important: Rust needs to know if you are adding numbers or joining words. Different types have different rules.

Simple explanation: You don’t put water in a paper bag. You use a bottle. Similarly, you use i32 for whole numbers, f64 for decimals, bool for true/false, and String for text.

Real-life example: A fuel gauge shows numbers. A name tag shows words. A light switch shows on/off (bool).

School example: Your report card has numbers for scores, letters for grades, and yes/no for attendance.

Home example: A TV remote has buttons for numbers (channels), on/off (bool), and volume (numbers).

Nigerian example: A market woman sells yams (counted in numbers), peppers (measured in cups), and “sold out” (true/false).

Table of common types:

TypeWhat it storesExample
i32Whole number (integer)42, -7, 0
f64Decimal number3.14, 2.5
boolTrue or falsetrue, false
StringText"Hello", "Lagos"
charSingle character'A', '7'

Mini summary: Data types keep your data organised. Rust checks that you use the right type.

Lesson 7: Mutability – Change or Not to Change?

Definition: Mutability means you can change the value of a variable. In Rust, variables are immutable (cannot change) by default. You must add mut to make them mutable.

Why it is important: Immutability prevents accidental changes. It makes programs safer and easier to understand.

Simple explanation: Imagine a pencil writing on paper. You can erase and rewrite (mutable). But a pen writes permanently (immutable). Rust starts with pen by default; you choose pencil with mut.

Real-life example: Your birthday date never changes (immutable). Your age changes every year (mutable).

School example: Your name is fixed (immutable). Your class teacher can change (mutable).

Home example: The number of chairs in your house can change when guests come (mutable). The address of your house is fixed (immutable).

Nigerian example: The price of fuel can change (mutable). The location of your house is fixed (immutable).

Illustration:

  let x = 5;        // immutable, cannot change
  // x = 10;        // ERROR!
  let mut y = 5;    // mutable
  y = 10;           // OK!
  

Mini summary: Use let for unchangeable variables. Use let mut for changeable ones. Rust loves safety.

Lesson 8: Functions – Reusable Blocks of Code

Definition: A function is a named block of code that does a specific job. You can call it many times.

Why it is important: Functions avoid repeating code. They make programs shorter and easier to fix.

Simple explanation: Think of a function as a recipe. You write it once, then use it whenever you want to cook that dish.

Real-life example: A tailor has a pattern for a shirt. He uses the same pattern for many customers (function calls).

School example: The school bell rings at the same time every day. It is like a function called “ringBell()”.

Home example: Your blender has a “smoothie” button. You press it, and it does the same steps each time.

Nigerian example: A taxi driver has a route from Ikeja to Yaba. He repeats the same route (function) for many passengers.

Illustration:

  fn greet() {
      println!("Hello, friend!");
  }

  fn main() {
      greet();   // calls the function
      greet();   // calls it again
  }
  

Mini summary: Functions are named blocks. Use fn to define them and () to call them.

Lesson 9: Comments – Notes for Humans

Definition: Comments are lines in your code that the computer ignores. They are for you and other humans to read.

Why it is important: Comments explain why you did something. They help you remember later and help others understand.

Simple explanation: Imagine writing notes in the margin of your school book. The teacher doesn’t mark them, but they help you study.

Real-life example: A recipe has notes like “bake for 20 minutes”. The oven ignores the note, but the cook reads it.

School example: Your class timetable might have small notes like “bring calculator”. They are comments for students.

Home example: A sticky note on the fridge says “buy milk”. It is a comment for the family.

Nigerian example: A signboard in traffic says “no parking”. It is a comment for drivers, not for the road.

Illustration:

  // This is a single-line comment
  let x = 5; // This comment explains the variable

  /*
     This is a multi-line comment.
     It can span many lines.
  */
  

Mini summary: Use // for short comments and /* ... */ for longer ones. They make code friendly.

Lesson 10: The Rust Compiler – Your Strict Friend

Definition: The compiler is a program that turns your Rust code into a program the computer can run. It also checks for mistakes.

Why it is important: The compiler catches many errors before you run the program. This saves time and prevents crashes.

Simple explanation: The compiler is like a teacher who checks your homework before you submit it. If there is a mistake, the teacher tells you to fix it.

Real-life example: A building inspector checks a house before people move in. The Rust compiler checks your code before it runs.

School example: Before a debate, your teacher checks your speech for errors. That is the compiler.

Home example: Before cooking, your mum checks if all ingredients are available. That is the compiler.

Nigerian example: Before a bus leaves the park, the conductor checks that all passengers have paid. The compiler checks your code.

Illustration:

  Your code (hello.rs)
       |
       V
  rustc hello.rs   <-- compiler
       |
       V
  If no errors: hello executable
  If errors: messages to fix
  

Mini summary: The Rust compiler is strict but helpful. It catches mistakes early. Always fix compiler errors.

Lesson 11: Cargo – Your Project Manager

Definition: Cargo is Rust’s tool for creating projects, building code, running tests, and adding libraries.

Why it is important: Without Cargo, managing big projects is hard. Cargo makes everything organised.

Simple explanation: Cargo is like a project folder with extra powers. It creates a structure, downloads dependencies, and runs your program.

Real-life example: A wedding planner organises the venue, food, and music. Cargo organises your Rust project.

School example: A class monitor collects homework and keeps things in order. Cargo is the monitor for your code.

Home example: A toolbox keeps all tools in one place. Cargo is your coding toolbox.

Nigerian example: An event planner for a Nigerian wedding handles aso-ebi, food, and canopies. Cargo handles your project’s files and libraries.

Illustration:

  cargo new my_project
       |
       V
  my_project/
    ├── Cargo.toml
    └── src/
         └── main.rs
  

Mini summary: Use cargo new to start a project. Use cargo run to run it. Cargo keeps everything tidy.

Lesson 12: Printing and Input – Talking with the Computer

Definition: Printing means showing text on the screen. Input means the computer reads what you type.

Why it is important: Programs need to communicate with people. Printing shows results. Input lets users give data.

Simple explanation: Printing is like speaking. Input is like listening. A good program does both.

Real-life example: An ATM prints your balance. It also takes your PIN as input.

School example: A teacher asks a question (input) and writes the answer on the board (print).

Home example: A TV remote takes input (button press) and prints the channel on screen.

Nigerian example: A POS machine takes your card details (input) and prints a receipt (output).

Illustration:

  use std::io;

  fn main() {
      println!("What is your name?");
      let mut name = String::new();
      io::stdin().read_line(&mut name).expect("Failed");
      println!("Hello, {}!", name.trim());
  }
  

Mini summary: Use println! to print. Use stdin().read_line to read input. Always trim extra spaces.

Lesson 13: Common Mistakes and How Rust Helps

Definition: Mistakes (bugs) are errors in code. Rust catches many before running.

Why it is important: Knowing common mistakes helps you avoid them.

Simple explanation: Rust is like a spell-checker. It underlines errors and suggests fixes.

Real-life example: Typing a wrong phone number. Rust checks if the number is valid.

School example: Forgetting to carry your pencil. Rust checks if you have all variables.

Home example: Forgetting to turn off the tap. Rust checks if memory is freed.

Nigerian example: Forgetting your change in a taxi. Rust checks that you don’t lose data.

Table of common mistakes:

MistakeWhat happensRust’s help
Using a variable without mutCannot change valueCompiler error
Forgetting semicolonUnexpected codeCompiler error
Wrong data typeType mismatchCompiler error
Reading input without trimExtra newlineYou must trim

Mini summary: Rust catches many mistakes early. Read compiler messages and fix them.

Lesson 14: Best Practices for Beginners

Definition: Best practices are good habits that make your code clean and safe.

Why it is important: Good habits make coding easier and more fun.

Simple explanation: Like brushing your teeth daily, coding habits keep your programs healthy.

Real-life example: Keeping your room tidy. Best practices keep code tidy.

School example: Writing neatly in your notebook. Best practices make code readable.

Home example: Washing plates after eating. Best practices prevent problems later.

Nigerian example: Keeping your market stall organised. Best practices keep code organised.

List of best practices:

  • Use meaningful variable names (e.g., score not s).
  • Write comments to explain why, not what.
  • Use cargo to manage projects.
  • Run your code often to catch errors early.
  • Read compiler errors carefully.
  • Keep functions small and focused.

Mini summary: Good habits make you a better programmer. Start them now.

Key Vocabulary

WordSimple Definition
Systems programmingWriting software that controls hardware and supports other programs.
RustA safe, fast programming language for systems.
CompilerA program that turns your code into a runnable program and checks for errors.
CargoRust’s tool for managing projects.
VariableA named box that stores a value.
Data typeThe kind of value a variable holds (number, text, true/false).
ImmutableCannot be changed.
MutableCan be changed.
FunctionA reusable block of code that does a job.
CommentA note in code that the computer ignores.
PrintShow text on the screen.
InputData typed by the user.
BugA mistake in code.
ConcurrencyDoing many things at the same time.

Important Concepts

  • Safety first: Rust prevents memory errors and data races.
  • Speed: Rust programs run as fast as C or C++.
  • Immutability by default: Variables cannot change unless you say mut.
  • Ownership and borrowing: (We will learn later, but it is Rust’s way of managing memory without a garbage collector.)
  • Cargo and crates: Cargo manages projects; crates are libraries you can use.
  • Compiler as teacher: The compiler catches many errors before running.

Step-by-step Explanations

How to write and run your first Rust program

  1. Install Rust from rustup.rs.
  2. Open a terminal or command prompt.
  3. Type cargo new hello_rust to create a project.
  4. Go into the folder: cd hello_rust.
  5. Open src/main.rs in a text editor.
  6. Replace the code with:
    fn main() {
        println!("Hello, World!");
    }
          
  7. Save the file.
  8. In the terminal, type cargo run.
  9. You will see Hello, World! on the screen.

Explanation: cargo new creates the project structure. cargo run compiles and runs your code. The main function is the starting point. println! prints text.

Real-life Examples

  • Banking: Rust is used in some banks to handle transactions safely.
  • Operating systems: Parts of Windows and Linux are being rewritten in Rust for safety.
  • Web browsers: Firefox uses Rust for its rendering engine.
  • Games: Some game engines use Rust for speed and safety.
  • Embedded devices: Rust runs on small chips in cars, robots, and IoT devices.

Nigerian Examples

  • POS machines: Many POS terminals in Nigeria need safe, fast software. Rust can power them.
  • Banking apps: Nigerian banks use secure systems. Rust helps prevent crashes and fraud.
  • Traffic lights in Lagos: Systems programming controls traffic lights. Rust can make them reliable.
  • Nollywood streaming: Video apps need to handle many users. Rust’s concurrency helps.
  • Agricultural sensors: Farmers use sensors to check soil. Rust can run on small devices.

Fun Examples Children Can Relate To

  • Video games: Rust makes games run smoothly without crashing.
  • Robots: Like Ada’s robot Chidi, Rust keeps robots from bumping into walls.
  • Chat apps: Sending messages without them getting lost.
  • Music players: Playing songs without skipping.
  • School quiz apps: Keeping score correctly.

Everyday Examples

  • Alarm clock: A program that checks the time and rings.
  • Microwave: A program that counts down and stops.
  • Traffic light: A program that changes lights on a timer.
  • ATM: A program that checks your PIN and gives cash.
  • Phone keyboard: A program that shows letters you tap.

Parent Tips

  • Encourage your child to ask questions. Curiosity is key in programming.
  • Install Rust together. It is free and safe.
  • Let them make mistakes. Errors are learning opportunities.
  • Praise effort, not just correct answers.
  • Use everyday examples (like traffic lights) to explain concepts.
  • Set a small daily coding time. Consistency helps.
  • Celebrate small wins, like printing “Hello, World!”.
  • Be patient. Learning to code takes time.

Interesting Facts

  • Rust was voted the “most loved programming language” on Stack Overflow for many years.
  • Rust’s mascot is a crab named Ferris.
  • Rust is named after a fungus that is tough and resilient.
  • Rust has no garbage collector, yet it manages memory safely.
  • Rust can run on tiny computers and huge servers.
  • Many companies pay high salaries for Rust developers.

Did You Know?

  • Did you know that Rust is used in space? Some satellites use Rust.
  • Did you know that the Linux kernel now supports Rust?
  • Did you know that Rust can help prevent hacking?
  • Did you know that cargo can run tests for your code automatically?
  • Did you know that Rust’s compiler gives very helpful error messages?

Remember This

  • Rust is safe, fast, and great for systems programming.
  • Variables store data. Use let to create them.
  • Use mut to make a variable changeable.
  • Functions are reusable blocks of code.
  • Comments help humans understand code.
  • The compiler checks your code before it runs.
  • Cargo manages your projects.
  • Practice every day to get better.

Common Mistakes

  • Forgetting semicolons at the end of statements.
  • Trying to change an immutable variable without mut.
  • Using the wrong data type (e.g., putting text in a number variable).
  • Forgetting to call main() correctly.
  • Not trimming input when reading from the user.
  • Ignoring compiler error messages.

Best Practices

  • Use meaningful names for variables and functions.
  • Write comments for tricky parts.
  • Keep functions short and focused.
  • Run cargo check often to catch errors.
  • Read the compiler messages carefully.
  • Format your code with cargo fmt.
  • Test your code with cargo test.

Illustrations and Diagrams

How Rust Works

  Your Code (main.rs)
        |
        V
  Rust Compiler (rustc)
        |
        +--> Errors? --> Fix and recompile
        |
        V
  Executable Program
        |
        V
  Runs on your computer
  

Rust Project Structure with Cargo

  my_project/
  ├── Cargo.toml    (project settings)
  └── src/
       └── main.rs  (your code)
  

Decision Flowchart: Should I use mut?

  Start
    |
    V
  Need to change the value later?
    |
    +-- Yes --> Use let mut x = ...
    |
    +-- No  --> Use let x = ...
    |
    V
  End
  

Comparison Tables

Rust vs Other Languages

FeatureRustPythonC++
SpeedVery fastSlowerVery fast
Memory safetyYes, compiler checksAutomatic, but slowerManual, error-prone
Learning curveModerateEasyHard
ConcurrencySafe and easyLimitedHard
Use caseSystems, embedded, webScripts, data scienceGames, systems

Immutable vs Mutable

PropertyImmutableMutable
Can change value?NoYes
Keywordletlet mut
SafetyHigherLower, but flexible
Examplelet x = 5;let mut y = 5; y = 10;

Lesson Summaries

Lesson 1: Systems programming controls hardware and supports apps. Rust is a great language for it.

Lesson 2: Rust is safe, fast, and concurrent. It prevents many crashes.

Lesson 3: Install Rust with rustup. You get rustc and cargo.

Lesson 4: “Hello, World!” prints a message. Every Rust program starts with fn main().

Lesson 5: Variables store data. Use let.

Lesson 6: Data types tell Rust what kind of value you have.

Lesson 7: Immutable by default. Use mut to change.

Lesson 8: Functions are reusable blocks of code.

Lesson 9: Comments are notes for humans.

Lesson 10: The compiler checks your code and finds errors.

Lesson 11: Cargo manages projects and libraries.

Lesson 12: Printing shows text. Input reads what you type.

Lesson 13: Common mistakes include missing semicolons and wrong types.

Lesson 14: Best practices make code clean and safe.

End-of-Module Summary

Congratulations! You have finished Module One. You learned that systems programming is the foundation of all software. Rust is a modern language that is safe, fast, and perfect for systems. You installed Rust, wrote your first program, and learned about variables, data types, mutability, functions, comments, the compiler, Cargo, and input/output. You also saw many examples from Nigeria and everyday life. You now know common mistakes and best practices. Most importantly, you are ready to write simple Rust programs and understand how they work. Keep practising, and you will become a great Rust programmer!

Frequently Asked Questions

  1. What is Rust? Rust is a programming language for building fast and safe software.
  2. Is Rust hard to learn? It is a bit stricter than some languages, but very beginner-friendly with practice.
  3. Do I need to know another language first? No. You can start with Rust.
  4. What is Cargo? Cargo is Rust’s tool for managing projects.
  5. Why do I need to use mut? To allow a variable to change. Rust defaults to safety.
  6. What is a compiler error? A message from Rust saying your code has a problem.
  7. Can Rust run on my phone? Yes, Rust can run on many devices.
  8. Is Rust free? Yes, completely free and open-source.
  9. What can I build with Rust? Games, operating systems, web servers, robots, and more.
  10. How do I get help? Read the compiler messages, ask a teacher, or search online.

Matching Exercises

Match the word to its definition.

WordDefinition
1. VariableA. A reusable block of code.
2. FunctionB. A named box that stores a value.
3. CompilerC. A note in code that the computer ignores.
4. CommentD. Turns code into a runnable program.
5. CargoE. Rust’s project manager.

Answers: 1-B, 2-A, 3-D, 4-C, 5-E

Scenario-based Exercises

  1. Scenario: You want to store your age in a program. Which data type should you use?
    Answer: i32 (whole number).
  2. Scenario: You need a variable that will change when you score a goal. Should it be mutable?
    Answer: Yes, use let mut score = 0;.
  3. Scenario: Your program asks for your name and prints it. What function do you use to read input?
    Answer: std::io::stdin().read_line().
  4. Scenario: You write let x = 5; x = 10; and get an error. Why?
    Answer: x is immutable. Use let mut x = 5;.
  5. Scenario: You want to reuse a block of code that greets users. What should you create?
    Answer: A function.

Group Activity

Title: “Build a Greeting Robot”

Instructions: In groups of 3–4, write a Rust program that asks for each person’s name and then prints a greeting for each. Use a function for the greeting. One person types, one person reads the compiler errors, one person explains the code. Share your program with the class.

Goal: Practice variables, input, functions, and printing.

Individual Activity

Task: Write a Rust program that stores your name, age, and favourite food in variables. Then print them in a sentence like: “My name is Ada, I am 13 years old, and I love jollof rice.”

Hint: Use let and println!.

Mini Project

Project: “My Daily Routine”

Write a Rust program that prints your daily routine. Use at least three functions: one for morning, one for afternoon, and one for evening. Call them in main(). Add comments to explain each part.

Example output:

  Morning: Wake up, brush teeth, eat breakfast.
  Afternoon: Go to school, study, play.
  Evening: Do homework, eat dinner, sleep.
  

Practical Assignment

Assignment: Create a new Cargo project called about_me. In main.rs, write a program that:

  1. Prints “What is your name?”
  2. Reads the user’s name.
  3. Prints “How old are you?”
  4. Reads the age.
  5. Prints a sentence: “Hello [name], you are [age] years old!”

Submit: Your main.rs file and a screenshot of the program running.

Key Takeaways

  • Rust is a safe, fast language for systems programming.
  • Install Rust with rustup and use cargo for projects.
  • Variables store data. Use let and mut.
  • Data types: i32, f64, bool, String, char.
  • Functions are reusable blocks.
  • Comments explain code to humans.
  • The compiler catches errors before running.
  • Print with println!, read input with stdin().read_line().
  • Practice and read error messages carefully.

Classroom Discussion Questions

  1. Why is safety important in systems programming?
  2. How is Rust’s compiler like a teacher?
  3. What would happen if traffic lights had bugs?
  4. Why does Rust make variables immutable by default?
  5. How can functions make code shorter?
  6. What is the difference between a variable and a constant?
  7. How does Cargo help in big projects?
  8. Why do we write comments?
  9. What did Ada learn from the broken robot story?
  10. Where do you see systems programming in Nigeria?

Preparation for Module Two

In Module Two, we will dive deeper into Rust. We will learn about:

  • Control flow: if, else, loops.
  • More data types and type conversion.
  • Ownership and borrowing (Rust’s superpower!).
  • Writing bigger programs.
  • Debugging and testing.

To prepare, make sure you have completed the practical assignment and can run simple Rust programs. Review your notes on variables and functions. Bring your curiosity!

See you in Module Two!


End of Module One – Rust Programming for Systems

3

Module Two

Rust Programming for Systems – Module Two

Module Two: Making Decisions and Repeating Actions – Control Flow in Rust

“Rust Programming for Systems” – A beginner’s course for curious minds

Module Introduction

Welcome back, young coder! In Module One, you learned what Rust is, how to install it, and how to write simple programs with variables and functions. You even made the computer talk with println!.

But a program that only runs straight from top to bottom is boring. Real programs need to make decisions and repeat things. Imagine a traffic light that never changes, or a game that never checks if you won. That would be useless!

In this module, we will learn two superpowers: decision making (using if, else, and match) and repeating actions (using loops). We will also peek at Rust’s most special idea: ownership. This is what makes Rust safe and fast. Don’t worry—we will use simple stories, examples from Nigeria, and lots of pictures made with text.

By the end, you will be able to write programs that think and act, just like a smart robot. Let’s begin!

Learning Objectives

After finishing this module, you will be able to:

  • Use if, else if, and else to make decisions in Rust.
  • Use match to compare a value against many patterns.
  • Use loop, while, and for to repeat actions.
  • Understand the difference between expressions and statements.
  • Explain the basics of ownership and borrowing in simple words.
  • Write programs that can make choices and repeat tasks.
  • Recognize common mistakes with control flow and ownership.
  • Complete a mini project and practical assignment.

Warm-up Story: Chidi the Robot Learns to Decide

Remember Ada and her robot Chidi from Module One? After Ada learned Rust, she rebuilt Chidi’s brain. Now Chidi could walk without crashing. But Chidi still had a problem: Chidi did not know when to stop walking!

One day, Ada took Chidi to the market in Lagos. Chidi was supposed to follow Ada and stop when she stopped. But Chidi just kept walking. Ada shouted, “Chidi, stop!” But Chidi did not understand.

Ada realized that Chidi needed to make decisions. Chidi needed to check: “Is Ada in front of me? If yes, keep walking. If no, stop.” Chidi also needed to repeat this check many times, like a loop.

So Ada wrote a new program using if and while. She taught Chidi to check Ada’s position again and again. Now Chidi could decide when to walk and when to stop. Chidi became the smartest robot in Lagos!

Moral of the story: Programs need to make decisions and repeat actions to be useful. Rust gives us tools like if, match, and loops to do this.

Main Lessons

Lesson 1: Making Decisions with if

Definition: if is a keyword that runs a block of code only when a condition is true.

Why it is important: Programs need to choose different actions in different situations. if lets them do that.

Simple explanation: Imagine you are hungry. You check: “If I am hungry, I will eat.” The action (eating) only happens if the condition (hungry) is true.

Real-life example: A traffic light: if the light is red, cars stop. If green, cars go.

School example: If you score above 50, you pass the exam. If not, you fail.

Home example: If the pot is hot, use a cloth to hold it. If not, hold it directly.

Nigerian example: If it rains in Lagos, take an umbrella. If not, leave it at home.

Illustration:

  let hungry = true;

  if hungry {
      println!("Time to eat!");
  }
  

Step-by-step:

  • Write if followed by a condition.
  • The condition must be a bool (true or false).
  • Open a block with { and close with }.
  • Put the code to run inside the block.

Mini summary: if runs code only when a condition is true. It is the first step to making your program smart.

Lesson 2: Adding else and else if

Definition: else runs when the if condition is false. else if checks another condition if the first one is false.

Why it is important: Sometimes you need more than two choices. else if lets you check many conditions in order.

Simple explanation: If you are hungry, eat. Else if you are thirsty, drink. Else, rest.

Real-life example: A grading system: if score >= 70, grade A; else if score >= 60, grade B; else, grade C.

School example: If it is Monday, wear uniform. Else if it is Friday, wear sports wear. Else, wear casual.

Home example: If there is rice, cook rice. Else if there is beans, cook beans. Else, order food.

Nigerian example: If there is fuel, drive the car. Else if there is diesel, use the generator. Else, take a bus.

Illustration:

  let score = 75;

  if score >= 70 {
      println!("Grade A");
  } else if score >= 60 {
      println!("Grade B");
  } else {
      println!("Grade C");
  }
  

Mini summary: else if lets you check many conditions. else catches everything else. Use them together for smart decisions.

Lesson 3: Conditions and Boolean Logic

Definition: A condition is an expression that is either true or false. Boolean logic uses && (AND), || (OR), and ! (NOT).

Why it is important: You often need to check more than one thing at once.

Simple explanation: && means both must be true. || means at least one must be true. ! flips true to false and false to true.

Real-life example: You can ride a bike if you have a helmet AND you know how to ride.

School example: You can go to the library if you have a library card OR a teacher’s note.

Home example: You can watch TV if you have finished homework AND it is not too late.

Nigerian example: You can travel if you have your ticket AND your luggage is ready.

Illustration:

  let has_helmet = true;
  let knows_riding = false;

  if has_helmet && knows_riding {
      println!("You can ride!");
  } else {
      println!("Not yet safe to ride.");
  }

  if !knows_riding {
      println!("You need to learn riding first.");
  }
  

Mini summary: Use &&, ||, and ! to combine or flip conditions. They make your decisions more powerful.

Lesson 4: The match Expression – A Better Way to Choose

Definition: match compares a value against many patterns and runs the code for the matching pattern.

Why it is important: It is cleaner and safer than many if else blocks. Rust checks that you cover all possibilities.

Simple explanation: Imagine a vending machine. You press a button (A1, B2, C3). The machine matches your button to a snack. match does the same with values.

Real-life example: A traffic light: match the colour to an action. Red -> stop, Yellow -> ready, Green -> go.

School example: Match the day of the week to the subject: Monday -> Maths, Tuesday -> English, etc.

Home example: Match the weather to what you wear: Sunny -> T-shirt, Rainy -> raincoat.

Nigerian example: Match the market day to the market you visit: Monday -> Oshodi, Wednesday -> Mile 12, etc.

Illustration:

  let light = "red";

  match light {
      "red" => println!("Stop!"),
      "yellow" => println!("Get ready..."),
      "green" => println!("Go!"),
      _ => println!("Unknown light"),
  }
  

Step-by-step:

  • Write match followed by the value.
  • Inside { }, write patterns with => and code.
  • Separate each arm with a comma.
  • Use _ as the “catch-all” pattern for anything else.

Mini summary: match is a clean way to choose between many options. It forces you to think of all cases.

Lesson 5: Repeating with loop

Definition: loop repeats a block of code forever until you tell it to stop with break.

Why it is important: Some tasks need to repeat many times, like checking for input or counting.

Simple explanation: Imagine a fan that keeps spinning until you press the off button. loop is like that fan. break is the off button.

Real-life example: A washing machine repeats the wash cycle until the timer ends.

School example: The school bell rings every day at the same time. It is a loop.

Home example: Your alarm clock rings every morning until you turn it off.

Nigerian example: A generator keeps running until you switch it off. loop is the generator, break is the switch.

Illustration:

  let mut count = 0;

  loop {
      println!("Count is {}", count);
      count += 1;

      if count == 5 {
          break;
      }
  }
  

Mini summary: loop repeats forever. Use break to stop. Be careful not to create an infinite loop by mistake!

Lesson 6: while Loops – Repeat While True

Definition: A while loop repeats as long as a condition is true.

Why it is important: It is perfect when you don’t know how many times to repeat, but you know when to stop.

Simple explanation: While you are hungry, keep eating. When you are full, stop.

Real-life example: While the traffic light is red, cars wait. When it turns green, they go.

School example: While the teacher is talking, students listen. When the bell rings, they go out.

Home example: While the water is boiling, watch the pot. When it boils, turn off the stove.

Nigerian example: While there is fuel in the generator, it runs. When the fuel finishes, it stops.

Illustration:

  let mut number = 3;

  while number != 0 {
      println!("{}!", number);
      number -= 1;
  }
  println!("Liftoff!");
  

Mini summary: while checks a condition before each repeat. When the condition becomes false, the loop stops.

Lesson 7: for Loops – Repeat a Known Number of Times

Definition: A for loop repeats once for each item in a collection (like a range of numbers).

Why it is important: It is the safest and most common loop in Rust. It avoids mistakes with counters.

Simple explanation: For each day of the week, go to school. For each item in your bag, take it out.

Real-life example: For each passenger on a bus, collect the fare.

School example: For each student in the class, mark attendance.

Home example: For each plate in the sink, wash it.

Nigerian example: For each customer in the market, greet them “Welcome o!”.

Illustration:

  for number in 1..5 {
      println!("Number is {}", number);
  }

  let names = ["Ada", "Tunde", "Chidi"];
  for name in names.iter() {
      println!("Hello, {}!", name);
  }
  

Mini summary: for loops go through each item. They are clean and safe. Use them when you know the collection.

Lesson 8: Expressions vs Statements

Definition: An expression produces a value. A statement performs an action but produces no value.

Why it is important: Rust is an expression-based language. Many things are expressions, like if and match.

Simple explanation: 5 + 3 is an expression (it gives 8). let x = 5; is a statement (it does something but gives nothing).

Real-life example: “What is 2+2?” is an expression (answer 4). “Close the door” is a statement (action, no value).

School example: “What is your name?” (expression, answer). “Raise your hand” (statement, action).

Home example: “How many eggs?” (expression). “Put the eggs in the basket” (statement).

Nigerian example: “How much is the yam?” (expression). “Buy the yam” (statement).

Illustration:

  let x = 5;          // statement
  let y = {           // block expression
      let a = 3;
      a + 1           // no semicolon, so it is the value
  };
  println!("y is {}", y); // prints 4
  

Mini summary: Expressions give values. Statements do actions. In Rust, if and match can be expressions if you use them that way.

Lesson 9: Using if in a let – Expressions in Action

Definition: You can assign the result of an if or match expression to a variable.

Why it is important: It makes code shorter and cleaner.

Simple explanation: Instead of writing a long if else to set a variable, you can do it in one line.

Real-life example: “If it is sunny, wear sunglasses; else, wear a raincoat.” Assign that choice to “what to wear”.

School example: “If score is above 50, result is Pass; else, Fail.” Assign to “result”.

Home example: “If there is milk, breakfast is cereal; else, breakfast is bread.” Assign to “breakfast”.

Nigerian example: “If there is petrol, drive the car; else, take a bus.” Assign to “transport”.

Illustration:

  let score = 75;
  let result = if score >= 50 { "Pass" } else { "Fail" };
  println!("Result: {}", result);
  

Mini summary: if and match can give values. Assign them to variables for cleaner code. Remember: no semicolon inside the block if you want the value.

Lesson 10: Introduction to Ownership – Rust’s Superpower

Definition: Ownership is Rust’s system for managing memory. Each value has a single owner. When the owner goes out of scope, the value is dropped (freed).

Why it is important: It prevents memory bugs and makes Rust safe without a garbage collector.

Simple explanation: Imagine you have a toy. Only one person can own it at a time. If you give it to a friend, you no longer own it. Rust does the same with data.

Real-life example: A book in the library. Only one person can borrow it at a time. When returned, someone else can borrow it.

School example: A class monitor holds the attendance book. If they give it to another student, they no longer have it.

Home example: The TV remote. If you pass it to your sister, you cannot change the channel anymore.

Nigerian example: A single mobile phone. If you give it to your friend to make a call, you cannot use it until they return it.

Illustration:

  let s1 = String::from("hello");
  let s2 = s1;   // s1 is moved to s2. s1 is no longer valid.
  // println!("{}", s1); // ERROR: s1 no longer owns the data
  println!("{}", s2);   // OK
  

Mini summary: Ownership means one owner at a time. When you assign a String to another variable, the original is moved. This prevents double-free errors.

Lesson 11: Borrowing – Using Without Taking

Definition: Borrowing lets you use a value without taking ownership. You use & to create a reference.

Why it is important: It lets functions use data without stealing it from the owner.

Simple explanation: You can let a friend look at your book without giving it away. They borrow it and give it back.

Real-life example: A library book you read in the library. You don’t own it, but you can read it.

School example: You borrow a pencil from a friend. You use it and return it.

Home example: You borrow your brother’s charger. You use it and give it back.

Nigerian example: You borrow a pot from your neighbour to cook. You return it after.

Illustration:

  fn main() {
      let s = String::from("hello");
      let len = calculate_length(&s); // borrow s
      println!("The length of '{}' is {}.", s, len);
  }

  fn calculate_length(s: &String) -> usize {
      s.len()
  }
  

Mini summary: Borrowing uses & to reference a value without moving it. The owner keeps ownership. This is safe and efficient.

Lesson 12: Mutable Borrowing – Changing Borrowed Data

Definition: You can borrow a value mutably with &mut if you want to change it.

Why it is important: Sometimes you need to modify data without taking ownership.

Simple explanation: You borrow a friend’s notebook and write in it with their permission.

Real-life example: A teacher borrows your homework to correct it. They can write on it (with permission).

School example: You borrow the class register to add your name. You need permission.

Home example: You borrow your mum’s phone to add a contact. She must allow it.

Nigerian example: You borrow a trader’s ledger to record a sale. The trader must agree.

Illustration:

  fn main() {
      let mut s = String::from("hello");
      change(&mut s);
      println!("{}", s); // prints "hello, world"
  }

  fn change(s: &mut String) {
      s.push_str(", world");
  }
  

Mini summary: Use &mut to borrow and change. You can only have one mutable borrow at a time. This prevents data races.

Lesson 13: Common Mistakes with Control Flow and Ownership

Definition: Mistakes (bugs) happen. Knowing them helps you avoid them.

Why it is important: Rust’s compiler catches many mistakes. Learn from the messages.

Simple explanation: Like learning to ride a bike, you may wobble. Rust helps you stay balanced.

Real-life example: Forgetting to turn off the tap. Rust checks that you don’t leave memory leaks.

School example: Forgetting to carry your homework. Rust checks that you don’t forget variables.

Home example: Forgetting to lock the door. Rust checks that your data is safe.

Nigerian example: Forgetting your change in a taxi. Rust checks that you don’t lose data.

Table of common mistakes:

MistakeWhat happensRust’s help
Using a moved valueValue no longer validCompiler error: “value borrowed after move”
Multiple mutable borrowsData race possibleCompiler error: “cannot borrow as mutable more than once”
Missing _ in matchNot all cases coveredCompiler error: “non-exhaustive patterns”
Infinite loop without breakProgram never stopsYou must add a break condition
Using == with different typesType mismatchCompiler error

Mini summary: Rust catches many mistakes early. Read the error messages. They tell you exactly what to fix.

Lesson 14: Best Practices for Control Flow and Ownership

Definition: Best practices are good habits that make your code clean and safe.

Why it is important: Good habits make coding easier and more fun.

Simple explanation: Like keeping your room tidy, best practices keep your code tidy.

Real-life example: A chef keeps the kitchen clean. A programmer keeps code clean.

School example: Writing neatly in your notebook. Best practices make code readable.

Home example: Washing plates after eating. Best practices prevent problems later.

Nigerian example: Keeping your market stall organised. Best practices keep code organised.

List of best practices:

  • Use for loops instead of while when possible. They are safer.
  • Use match instead of long if else chains.
  • Borrow with & instead of moving when you don’t need ownership.
  • Keep functions small and focused.
  • Use meaningful names for variables and functions.
  • Write comments to explain why, not what.
  • Run cargo check often to catch errors.

Mini summary: Good habits make you a better programmer. Start them now.

Lesson 15: Putting It All Together – A Small Program

Let’s write a program that uses everything we learned: if, match, loops, and borrowing.

Program: Guess the Number (simplified)

  use std::io;

  fn main() {
      let secret = 7;
      let mut attempts = 0;

      loop {
          println!("Guess a number between 1 and 10:");
          let mut guess = String::new();
          io::stdin().read_line(&mut guess).expect("Failed to read");
          let guess: i32 = guess.trim().parse().expect("Not a number");

          attempts += 1;

          if guess == secret {
              println!("You win! You took {} attempts.", attempts);
              break;
          } else if guess < secret {
              println!("Too low!");
          } else {
              println!("Too high!");
          }
      }
  }
  

Explanation:

  • loop repeats until the correct guess.
  • if else if else checks the guess.
  • break exits the loop when correct.
  • String::new() creates a new string.
  • parse() converts text to a number.
  • trim() removes extra spaces.

Mini summary: This program combines decisions, loops, and input. You can build it and play!

Key Vocabulary

WordSimple Definition
Control flowThe order in which code runs. Decisions and loops change it.
ifRuns code when a condition is true.
elseRuns code when the if condition is false.
else ifChecks another condition if the first is false.
matchCompares a value to many patterns.
loopRepeats forever until break.
whileRepeats while a condition is true.
forRepeats for each item in a collection.
ExpressionProduces a value.
StatementPerforms an action, no value.
OwnershipEach value has one owner. When owner goes away, value is dropped.
BorrowingUsing a value without taking ownership (&).
Mutable borrowBorrowing to change (&mut).
MoveTransferring ownership from one variable to another.
ScopeThe part of code where a variable is valid.

Important Concepts

  • Conditions: if and else use bool values.
  • Pattern matching: match is powerful and safe.
  • Loops: loop, while, and for repeat actions.
  • Expressions: Rust is expression-based. if and match can give values.
  • Ownership: One owner at a time. Prevents memory bugs.
  • Borrowing: Use & to reference without moving. Use &mut to change.
  • Compiler as guard: Rust checks ownership and borrowing rules at compile time.

Step-by-step Explanations

How to use match step by step

  1. Identify the value you want to check.
  2. Write match value {.
  3. List each possible pattern with => and the code to run.
  4. Separate arms with commas.
  5. Add a catch-all _ if needed.
  6. Close with }.

Example:

  let day = "Monday";
  match day {
      "Monday" => println!("Start of week"),
      "Friday" => println!("Almost weekend"),
      _ => println!("Just another day"),
  }
  

How to borrow step by step

  1. Create a variable that owns a value.
  2. Write a function that takes a reference: fn my_func(s: &String).
  3. Call the function with &my_variable.
  4. Inside the function, use the reference without taking ownership.
  5. The owner keeps ownership and can use the value after.

Example:

  fn main() {
      let s = String::from("hello");
      print_length(&s);
      println!("Still own: {}", s);
  }
  fn print_length(s: &String) {
      println!("Length: {}", s.len());
  }
  

Real-life Examples

  • Traffic lights: Use match to decide stop, ready, or go.
  • Bank ATMs: Use if to check if PIN is correct.
  • Game loops: Use loop to keep the game running until you quit.
  • Music players: Use for to play each song in a playlist.
  • Online forms: Use while to keep asking until valid input.

Nigerian Examples

  • POS machine: Uses if to check if card is valid.
  • Traffic in Lagos: Uses match to decide when to stop and go.
  • Market trading: Uses while to keep selling while there is stock.
  • Nollywood streaming: Uses for to play each episode.
  • Generator: Uses loop to keep running until fuel finishes.

Fun Examples Children Can Relate To

  • Video games: if checks if you won or lost.
  • Robot: while keeps the robot moving while battery is full.
  • Chat apps: loop keeps the app running until you close it.
  • Music: for plays each song in your playlist.
  • School quiz: match checks your answer against the correct one.

Everyday Examples

  • Alarm clock: while time is not up, keep ringing.
  • Microwave: for each second, count down.
  • Traffic light: match colour to action.
  • ATM: if PIN is correct, allow withdrawal.
  • Phone keyboard: for each tap, show letter.

Parent Tips

  • Encourage your child to explain their code out loud. It helps them learn.
  • Let them make mistakes. Errors are learning opportunities.
  • Use everyday examples (traffic lights, cooking) to explain control flow.
  • Set a small daily coding time. Consistency helps.
  • Celebrate small wins, like making a working loop.
  • Be patient. Ownership takes time to understand.
  • Ask them to teach you what they learned. Teaching is the best way to learn.
  • Keep it fun. Use games and stories.

Interesting Facts

  • Rust’s ownership system was inspired by research from the 1990s.
  • Rust prevents data races at compile time. No other language does this as well.
  • The match keyword is one of Rust’s most loved features.
  • Rust’s for loop is safer than C’s for loop.
  • Rust’s compiler is often called “the best teacher” because of its clear error messages.
  • Many companies rewrite their software in Rust to stop crashes.

Did You Know?

  • Did you know that Rust can prevent entire classes of bugs before your program runs?
  • Did you know that the Linux kernel now uses Rust for some drivers?
  • Did you know that Rust’s match must cover every possible case?
  • Did you know that loop can return a value with break?
  • Did you know that borrowing is checked at compile time, so there is no runtime cost?

Remember This

  • if, else if, and else make decisions.
  • match compares against many patterns.
  • loop repeats forever; use break to stop.
  • while repeats while a condition is true.
  • for repeats for each item in a collection.
  • Expressions give values; statements do actions.
  • Ownership: one owner at a time.
  • Borrowing: use & to reference, &mut to change.
  • Rust’s compiler catches many mistakes before running.

Common Mistakes

  • Forgetting to add break in a loop.
  • Using a moved value after moving it.
  • Trying to have two mutable borrows at the same time.
  • Forgetting the catch-all _ in match.
  • Using = instead of == in conditions.
  • Forgetting that if conditions must be bool.
  • Not trimming input before parsing.
  • Ignoring compiler error messages.

Best Practices

  • Prefer for loops over while when possible.
  • Use match instead of long if else chains.
  • Borrow instead of moving when you don’t need ownership.
  • Keep functions small and focused.
  • Use meaningful names.
  • Write comments for tricky parts.
  • Run cargo check often.
  • Read compiler messages carefully.
  • Format your code with cargo fmt.
  • Test your code with cargo test.

Illustrations and Diagrams

Control Flow Decision Tree

  Start
    |
    V
  Is condition true? --Yes--> Run if block
    |
    No
    |
    V
  Is else if condition true? --Yes--> Run else if block
    |
    No
    |
    V
  Run else block
    |
    V
  End
  

Loop Flowchart

  Start
    |
    V
  Check condition (while) or enter loop
    |
    +--> Condition false? --> Exit loop
    |
    +--> Condition true? --> Run loop body
              |
              V
         Go back to check
  

Ownership and Borrowing

  let s = String::from("hello");   // s owns the String
        |
        V
  let r = &s;                      // r borrows s
        |
        V
  println!("{}", r);               // OK
  println!("{}", s);               // OK, s still owns
  

Move Semantics

  let s1 = String::from("hello");
        |
        V
  let s2 = s1;   // ownership moves to s2
        |
        V
  s1 is no longer valid
        |
        V
  s2 is the new owner
  

Comparison Tables

Loop Comparison

Loop TypeWhen to UseExample
loopRepeat forever until breakGame loop
whileRepeat while condition is trueWait for input
forRepeat for each itemGo through a list

Ownership vs Borrowing

FeatureOwnershipBorrowing
Who has the value?One ownerOwner keeps it
Can you change?Yes, if mutableOnly with &mut
CostMove transfers ownershipNo move, just reference
SafetyPrevents double-freePrevents data races

Expression vs Statement

ExpressionStatement
Produces a valuePerforms an action
5 + 3let x = 5;
if true { 1 } else { 2 }println!("hi");

Lesson Summaries

Lesson 1: if runs code when a condition is true.

Lesson 2: else if and else add more choices.

Lesson 3: Use &&, ||, and ! to combine conditions.

Lesson 4: match compares a value to many patterns.

Lesson 5: loop repeats forever until break.

Lesson 6: while repeats while a condition is true.

Lesson 7: for repeats for each item in a collection.

Lesson 8: Expressions give values; statements do actions.

Lesson 9: if and match can be assigned to variables.

Lesson 10: Ownership: one owner at a time. Moving transfers ownership.

Lesson 11: Borrowing uses & to reference without moving.

Lesson 12: Mutable borrowing uses &mut to change borrowed data.

Lesson 13: Common mistakes include moved values and missing _ in match.

Lesson 14: Best practices: use for, match, and borrow when possible.

Lesson 15: Combine decisions, loops, and borrowing in a guessing game.

End-of-Module Summary

Congratulations! You have finished Module Two. You learned how to make programs think with if, else, and match. You learned how to repeat actions with loop, while, and for. You also learned Rust’s superpower: ownership and borrowing. These ideas make Rust safe and fast. You saw many examples from Nigeria and everyday life. You now know common mistakes and best practices. Most importantly, you can write programs that make decisions and repeat tasks. Keep practising, and you will become a great Rust programmer!

Frequently Asked Questions

  1. What is control flow? The order in which code runs. Decisions and loops change it.
  2. What is the difference between if and match? if checks one condition. match checks many patterns.
  3. When should I use loop vs while? Use loop when you want to repeat forever until a break. Use while when you have a condition.
  4. What is ownership? Rust’s system where each value has one owner. When the owner goes away, the value is dropped.
  5. What is borrowing? Using a value without taking ownership. You use &.
  6. What is a mutable borrow? Borrowing to change the value. You use &mut.
  7. Why can’t I have two mutable borrows? It could cause data races. Rust prevents this at compile time.
  8. What is an expression? Code that produces a value.
  9. What is a statement? Code that performs an action but produces no value.
  10. How do I stop an infinite loop? Use break.

Matching Exercises

Match the word to its definition.

WordDefinition
1. ifA. Repeats for each item in a collection.
2. matchB. Runs code when a condition is true.
3. whileC. Compares a value to many patterns.
4. forD. Repeats while a condition is true.
5. OwnershipE. Each value has one owner.

Answers: 1-B, 2-C, 3-D, 4-A, 5-E

Scenario-based Exercises

  1. Scenario: You want to check if a student passed or failed. Which control flow do you use?
    Answer: if else.
  2. Scenario: You want to check the day of the week and print a message for each day. Which control flow is best?
    Answer: match.
  3. Scenario: You want to keep asking for a password until it is correct. Which loop?
    Answer: loop or while.
  4. Scenario: You have a list of names and want to greet each one. Which loop?
    Answer: for.
  5. Scenario: You want to use a String in a function but keep ownership. What do you use?
    Answer: Borrow with &.

Group Activity

Title: “Build a Traffic Light Simulator”

Instructions: In groups of 3–4, write a Rust program that simulates a traffic light. Use match to choose the action for “red”, “yellow”, and “green”. Use a loop to repeat the cycle. Print the light colour and the action. Share your program with the class.

Goal: Practice match, loops, and printing.

Individual Activity

Task: Write a Rust program that asks the user for a number. Use if else to print whether the number is positive, negative, or zero. Use a loop to let the user try again until they type “quit”.

Hint: Use parse() to convert input to a number. Use break to exit.

Mini Project

Project: “My School Timetable”

Write a Rust program that stores your school timetable for the week. Use match to print the subject for each day. Use a for loop to go through the days. Add comments to explain each part.

Example output:

  Monday: Maths
  Tuesday: English
  Wednesday: Science
  Thursday: History
  Friday: Sports
  

Practical Assignment

Assignment: Create a new Cargo project called number_guess. In main.rs, write a program that:

  1. Stores a secret number (e.g., 7).
  2. Uses a loop to ask the user to guess.
  3. Reads the guess and converts it to a number.
  4. Uses if else if else to say “Too low!”, “Too high!”, or “You win!”.
  5. Breaks the loop when the guess is correct.
  6. Prints the number of attempts.

Submit: Your main.rs file and a screenshot of the program running.

Key Takeaways

  • Use if, else if, and else for decisions.
  • Use match for many patterns.
  • Use loop, while, and for for repetition.
  • Expressions give values; statements do actions.
  • Ownership: one owner at a time.
  • Borrowing: use & to reference, &mut to change.
  • Rust’s compiler catches many mistakes early.
  • Practice and read error messages carefully.

Classroom Discussion Questions

  1. Why do programs need to make decisions?
  2. How is match different from if else?
  3. What happens if a loop has no break?
  4. Why is for often safer than while?
  5. What is the difference between an expression and a statement?
  6. Why does Rust have ownership?
  7. How does borrowing help us use data without moving it?
  8. Why can’t we have two mutable borrows at the same time?
  9. What did Chidi the robot learn in the warm-up story?
  10. Where do you see control flow in Nigeria?

Preparation for Module Three

In Module Three, we will dive deeper into Rust. We will learn about:

  • Structs and enums (building your own data types).
  • Pattern matching with enums.
  • Error handling with Result and Option.
  • Modules and packages.
  • Writing bigger programs.
  • Testing and debugging.

To prepare, make sure you have completed the practical assignment and can write programs with decisions and loops. Review your notes on ownership and borrowing. Bring your curiosity!

See you in Module Three!


End of Module Two – Rust Programming for Systems

4

Module Three

Rust Programming for Systems – Module Three

Module Three: Building Your Own Types – Structs, Enums, and Error Handling

“Rust Programming for Systems” – A beginner’s course for curious minds

Module Introduction

Welcome back, young coder! In Module One, you learned how to store data in variables. In Module Two, you learned how to make decisions and repeat actions. Now it is time to build your own data types.

Imagine you are building a school management program. You need to store information about students: their names, ages, classes, and scores. If you use separate variables for each piece of information, your code will become a big, messy pile. Rust gives you a better way: structs and enums.

A struct groups related data together. An enum lets you choose one value from a list of possibilities. Together, they help you build clear, safe programs. We will also learn about error handling with Result and Option. These are Rust’s tools for handling things that might go wrong, without crashing.

By the end of this module, you will be able to design your own data types and write programs that handle errors gracefully. Let’s get started!

Learning Objectives

After finishing this module, you will be able to:

  • Define and use structs to group related data.
  • Add methods to structs using impl blocks.
  • Define and use enums to represent choices.
  • Use match with enums for pattern matching.
  • Understand Option and Result for error handling.
  • Use unwrap, expect, and ? operator safely.
  • Write programs that handle errors without crashing.
  • Complete a mini project and practical assignment.

Warm-up Story: Tunde Builds a School Register

Tunde is a bright boy in Abuja. His teacher asked him to keep a register of all the students in his class. At first, Tunde used a separate notebook for each student. He wrote name in one book, age in another, and score in another. Soon, the books were everywhere. He mixed up names and scores. It was a mess!

Tunde’s friend, Ada, said, “Tunde, why don’t you use one card for each student? Write the name, age, and score on the same card. Then you can keep all cards in one box.”

Tunde tried it. It was much better! Each card held all the information about one student. He could look at a card and see everything at once. He could also write notes on the card, like “Good in Maths” or “Needs help in English.”

In Rust, that card is called a struct. It groups related data together. And the notes are like methods—actions you can do with the card. Tunde’s new register was clean, safe, and easy to use. Just like Rust!

Moral of the story: Grouping related data together makes programs clean and safe. Structs help us do that.

Main Lessons

Lesson 1: What is a Struct?

Definition: A struct is a custom data type that groups related values together. Each value is called a field.

Why it is important: It keeps related data together, making code clean and easy to understand.

Simple explanation: Think of a student ID card. It has a name, age, class, and photo. All that information belongs to one student. A struct is like that card.

Real-life example: A bank account has a name, account number, and balance. All in one place.

School example: A student record with name, age, class, and score.

Home example: A recipe card with ingredients, steps, and cooking time.

Nigerian example: A market stall record with trader name, goods, price, and quantity.

Illustration:

  struct Student {
      name: String,
      age: u32,
      score: f64,
  }
  

Step-by-step:

  • Write struct followed by the name (use PascalCase: Student).
  • Open a block with { }.
  • List each field as name: Type.
  • Separate fields with commas.

Mini summary: A struct groups related data. It is like a card that holds many pieces of information about one thing.

Lesson 2: Creating and Using Struct Instances

Definition: An instance is a specific value created from a struct. You fill in the fields with actual data.

Why it is important: You need to create instances to use your structs in programs.

Simple explanation: The struct is the blank card. The instance is the card filled with a student’s details.

Real-life example: A blank form becomes an instance when you fill it with your name and address.

School example: A blank report card becomes an instance when it has your scores.

Home example: A shopping list becomes an instance when you write specific items.

Nigerian example: A blank POS receipt becomes an instance when it shows a transaction.

Illustration:

  let student1 = Student {
      name: String::from("Ada"),
      age: 13,
      score: 85.5,
  };

  println!("Name: {}", student1.name);
  println!("Age: {}", student1.age);
  println!("Score: {}", student1.score);
  

Mini summary: Create an instance by filling in the fields. Use dot notation to access fields.

Lesson 3: Methods – Actions on Structs

Definition: A method is a function that belongs to a struct. It is defined inside an impl block.

Why it is important: Methods let you do things with your data in a clean way.

Simple explanation: If the struct is a card, methods are actions you can do with the card, like “show details” or “update score.”

Real-life example: A phone has methods: call, send message, take photo.

School example: A student card has a method: “calculate grade.”

Home example: A TV remote has methods: turn on, change channel, volume up.

Nigerian example: A POS machine has methods: accept payment, print receipt.

Illustration:

  impl Student {
      fn show_details(&self) {
          println!("Name: {}, Age: {}, Score: {}", self.name, self.age, self.score);
      }

      fn is_pass(&self) -> bool {
          self.score >= 50.0
      }
  }
  

Step-by-step:

  • Write impl StructName { }.
  • Inside, write fn method_name(&self) { }.
  • &self means the method borrows the instance.
  • Call it with instance.method_name().

Mini summary: Methods are functions inside impl. They make structs powerful and clean.

Lesson 4: What is an Enum?

Definition: An enum (enumeration) is a type that can be one of several variants.

Why it is important: It represents choices clearly and safely.

Simple explanation: Think of a traffic light. It can be Red, Yellow, or Green. Those are the only choices. An enum lists all possible choices.

Real-life example: Days of the week: Monday, Tuesday, Wednesday, etc.

School example: Grades: A, B, C, D, F.

Home example: Light switch: On or Off.

Nigerian example: Payment methods: Cash, Transfer, Card, USSD.

Illustration:

  enum TrafficLight {
      Red,
      Yellow,
      Green,
  }

  enum PaymentMethod {
      Cash,
      Transfer,
      Card,
      USSD,
  }
  

Mini summary: Enums list possible choices. They make your code safe because you can only use the listed variants.

Lesson 5: Enums with Data

Definition: Enum variants can hold data. This makes enums very powerful.

Why it is important: Sometimes a choice comes with extra information.

Simple explanation: A payment can be Cash (with amount) or Card (with card number). The enum variant holds the data.

Real-life example: A message can be Text (with words), Image (with pixels), or Video (with frames).

School example: A result can be Pass (with score) or Fail (with reason).

Home example: A delivery can be Delivered (with time) or Pending (with expected date).

Nigerian example: A transfer can be Successful (with reference) or Failed (with error).

Illustration:

  enum Payment {
      Cash(f64),
      Transfer { bank: String, amount: f64 },
      Card(String),
  }
  

Mini summary: Enum variants can carry data. This lets you attach extra information to each choice.

Lesson 6: Pattern Matching with Enums

Definition: match works with enums to handle each variant.

Why it is important: It ensures you handle all possible variants safely.

Simple explanation: If the light is Red, stop. If Yellow, ready. If Green, go. match checks each variant.

Real-life example: A restaurant order: match the order to the kitchen action.

School example: Match the grade to a message: A -> Excellent, B -> Good, etc.

Home example: Match the weather to what to wear.

Nigerian example: Match the market day to the market location.

Illustration:

  let light = TrafficLight::Red;

  match light {
      TrafficLight::Red => println!("Stop!"),
      TrafficLight::Yellow => println!("Get ready..."),
      TrafficLight::Green => println!("Go!"),
  }
  

Mini summary: match with enums is safe and clean. Rust forces you to handle every variant.

Lesson 7: Option – Handling Missing Values

Definition: Option is an enum that can be Some(value) or None.

Why it is important: It handles cases where a value might be missing, without using null.

Simple explanation: Imagine a box that may or may not have a gift. Some(gift) means there is a gift. None means empty.

Real-life example: A phone contact that may or may not have an email address.

School example: A student may or may not have a middle name.

Home example: A fridge may or may not have milk.

Nigerian example: A market stall may or may not have tomatoes today.

Illustration:

  let some_number = Some(5);
  let no_number: Option = None;

  match some_number {
      Some(n) => println!("Number is {}", n),
      None => println!("No number"),
  }
  

Mini summary: Option handles missing values. Use Some and None. Always match both.

Lesson 8: Result – Handling Errors

Definition: Result is an enum that can be Ok(value) or Err(error).

Why it is important: It handles operations that might fail, like reading a file or parsing a number.

Simple explanation: Imagine you are baking. The cake might come out well (Ok) or burn (Err). Result tells you which happened.

Real-life example: An ATM withdrawal: Ok(cash) or Err("Insufficient funds").

School example: An exam: Ok(score) or Err("Absent").

Home example: A phone call: Ok("Connected") or Err("No network").

Nigerian example: A transfer: Ok("Successful") or Err("Network failure").

Illustration:

  fn divide(a: f64, b: f64) -> Result {
      if b == 0.0 {
          Err(String::from("Cannot divide by zero"))
      } else {
          Ok(a / b)
      }
  }

  match divide(10.0, 2.0) {
      Ok(result) => println!("Result: {}", result),
      Err(e) => println!("Error: {}", e),
  }
  

Mini summary: Result handles success and failure. Use Ok for success and Err for errors. Always handle both.

Lesson 9: unwrap and expect – Quick but Risky

Definition: unwrap() and expect() extract the value from Option or Result. If there is no value, the program panics (crashes).

Why it is important: They are quick for testing, but risky for real programs.

Simple explanation: Imagine opening a box. If there is a gift, you take it. If empty, you scream and fall down. That is unwrap.

Real-life example: Pressing an elevator button. If it works, fine. If not, you are stuck.

School example: Assuming you will pass without studying. If you fail, you panic.

Home example: Assuming there is fuel in the generator. If not, it stops.

Nigerian example: Assuming there is network before a transfer. If not, it fails.

Illustration:

  let x = Some(5);
  let y = x.unwrap(); // y = 5

  let z: Option = None;
  // let w = z.unwrap(); // PANIC! Program crashes
  

Mini summary: unwrap and expect are quick but dangerous. Use them only when you are sure there is a value. In real programs, use match or ?.

Lesson 10: The ? Operator – Safe Error Propagation

Definition: The ? operator returns the value if Ok, or returns the error if Err.

Why it is important: It makes error handling clean without match every time.

Simple explanation: If something works, continue. If it fails, pass the problem up to the caller.

Real-life example: A relay race. If a runner falls, the next runner takes over the problem.

School example: If you don’t understand a topic, ask the teacher. The teacher handles it.

Home example: If the remote is not working, give it to your dad. He fixes it.

Nigerian example: If the POS fails, the cashier calls the bank. The bank handles it.

Illustration:

  fn read_number() -> Result {
      let s = "42";
      let n: i32 = s.parse().map_err(|_| "Not a number".to_string())?;
      Ok(n)
  }
  

Mini summary: The ? operator propagates errors cleanly. Use it in functions that return Result.

Lesson 11: Structs with Methods and Enums Together

Definition: You can use structs and enums together to build powerful data models.

Why it is important: Real programs need both grouping and choices.

Simple explanation: A student struct with a field that is an enum for grade.

Real-life example: A car with a field for fuel type: Petrol, Diesel, Electric.

School example: A student with a field for result: Pass, Fail, Pending.

Home example: A delivery with a field for status: Ordered, Shipped, Delivered.

Nigerian example: A transaction with a field for payment method: Cash, Transfer, Card, USSD.

Illustration:

  enum Grade {
      A,
      B,
      C,
      F,
  }

  struct Student {
      name: String,
      age: u32,
      grade: Grade,
  }

  impl Student {
      fn show(&self) {
          println!("{} is {} years old", self.name, self.age);
          match self.grade {
              Grade::A => println!("Excellent!"),
              Grade::B => println!("Good job!"),
              Grade::C => println!("Keep trying!"),
              Grade::F => println!("Needs improvement."),
          }
      }
  }
  

Mini summary: Combine structs and enums for rich data. Use match to handle enum fields.

Lesson 12: Deriving Traits – Making Structs Useful

Definition: Traits are like abilities. Rust can automatically add some traits to your structs with #[derive(...)].

Why it is important: It saves you time and makes your structs work with printing, comparing, and cloning.

Simple explanation: Like a student automatically getting a library card when they join school. derive gives your struct automatic abilities.

Real-life example: A new phone automatically has calling and texting. You don’t build it from scratch.

School example: A new student automatically gets a uniform and timetable.

Home example: A new TV automatically has a remote.

Nigerian example: A new POS machine automatically accepts cards and prints receipts.

Illustration:

  #[derive(Debug, Clone, PartialEq)]
  struct Point {
      x: i32,
      y: i32,
  }

  let p1 = Point { x: 1, y: 2 };
  let p2 = p1.clone();
  println!("{:?}", p1); // Debug printing
  

Mini summary: #[derive(...)] adds traits like Debug, Clone, and PartialEq. It makes structs easier to use.

Lesson 13: Common Mistakes with Structs and Enums

Definition: Mistakes happen. Knowing them helps you avoid them.

Why it is important: Rust’s compiler catches many mistakes. Learn from the messages.

Simple explanation: Like forgetting to fill a form correctly. Rust tells you what is missing.

Real-life example: Forgetting to sign a cheque. The bank rejects it.

School example: Forgetting to write your name on an exam. The teacher cannot mark it.

Home example: Forgetting to close the fridge. Food spoils.

Nigerian example: Forgetting to add the recipient’s name in a transfer. The money returns.

Table of common mistakes:

MistakeWhat happensRust’s help
Forgetting to handle NoneCompiler error“non-exhaustive patterns”
Using unwrap on NoneProgram panicsRuntime crash
Missing a field in structCompiler error“missing field”
Wrong type in enum variantCompiler error“mismatched types”
Forgetting &self in methodCompiler error“expected &self”

Mini summary: Rust catches many mistakes early. Read the error messages. They tell you exactly what to fix.

Lesson 14: Best Practices for Structs, Enums, and Errors

Definition: Best practices are good habits that make your code clean and safe.

Why it is important: Good habits make coding easier and more fun.

Simple explanation: Like keeping your room tidy, best practices keep your code tidy.

Real-life example: A chef keeps the kitchen clean. A programmer keeps code clean.

School example: Writing neatly in your notebook. Best practices make code readable.

Home example: Washing plates after eating. Best practices prevent problems later.

Nigerian example: Keeping your market stall organised. Best practices keep code organised.

List of best practices:

  • Use structs to group related data.
  • Use enums for choices.
  • Use match to handle all variants.
  • Use Option for missing values, not null.
  • Use Result for operations that can fail.
  • Avoid unwrap in real programs.
  • Use ? to propagate errors cleanly.
  • Derive Debug for easy printing.
  • Keep methods small and focused.
  • Write comments to explain why.

Mini summary: Good habits make you a better programmer. Start them now.

Lesson 15: Putting It All Together – A Small Program

Let’s write a program that uses structs, enums, methods, and error handling.

Program: Student Report Card

  #[derive(Debug)]
  enum Grade {
      A,
      B,
      C,
      F,
  }

  struct Student {
      name: String,
      age: u32,
      score: f64,
      grade: Grade,
  }

  impl Student {
      fn new(name: &str, age: u32, score: f64) -> Student {
          let grade = if score >= 70.0 {
              Grade::A
          } else if score >= 60.0 {
              Grade::B
          } else if score >= 50.0 {
              Grade::C
          } else {
              Grade::F
          };

          Student {
              name: String::from(name),
              age,
              score,
              grade,
          }
      }

      fn show(&self) {
          println!("Name: {}", self.name);
          println!("Age: {}", self.age);
          println!("Score: {}", self.score);
          match self.grade {
              Grade::A => println!("Grade: A (Excellent)"),
              Grade::B => println!("Grade: B (Good)"),
              Grade::C => println!("Grade: C (Average)"),
              Grade::F => println!("Grade: F (Fail)"),
          }
      }
  }

  fn main() {
      let s1 = Student::new("Ada", 13, 85.0);
      let s2 = Student::new("Tunde", 14, 45.0);

      s1.show();
      println!("---");
      s2.show();
  }
  

Explanation:

  • Grade is an enum with four variants.
  • Student is a struct with name, age, score, and grade.
  • new is a method that creates a Student and calculates the grade.
  • show is a method that prints the details and matches the grade.
  • main creates two students and shows their reports.

Mini summary: This program combines structs, enums, methods, and match. It is a complete example of what you can build.

Key Vocabulary

WordSimple Definition
StructA custom type that groups related data.
FieldA piece of data inside a struct.
InstanceA specific value created from a struct.
MethodA function that belongs to a struct.
implA block where you define methods for a struct.
EnumA type that can be one of several variants.
VariantOne of the possible choices in an enum.
OptionAn enum for values that may be missing: Some or None.
ResultAn enum for success or failure: Ok or Err.
unwrapExtracts value or panics if empty.
expectLike unwrap but with a custom message.
? operatorPropagates errors cleanly.
TraitAn ability or behaviour that types can have.
deriveAutomatically adds traits to a struct or enum.
PanicWhen a program crashes due to an unrecoverable error.

Important Concepts

  • Structs: Group related data into one type.
  • Methods: Functions that belong to a struct, defined in impl.
  • Enums: Represent choices with variants.
  • Pattern matching: match handles all enum variants safely.
  • Option: Handles missing values without null.
  • Result: Handles operations that can fail.
  • ? operator: Propagates errors cleanly.
  • Deriving traits: Adds abilities like Debug and Clone automatically.
  • Compiler as guard: Rust checks that you handle all cases.

Step-by-step Explanations

How to define and use a struct step by step

  1. Write struct Name { }.
  2. List fields as field: Type.
  3. Create an instance with Name { field: value, ... }.
  4. Access fields with instance.field.
  5. Add methods in impl Name { }.
  6. Call methods with instance.method().

Example:

  struct Book {
      title: String,
      author: String,
      pages: u32,
  }

  impl Book {
      fn summary(&self) -> String {
          format!("{} by {} ({} pages)", self.title, self.author, self.pages)
      }
  }

  fn main() {
      let b = Book {
          title: String::from("Things Fall Apart"),
          author: String::from("Chinua Achebe"),
          pages: 209,
      };
      println!("{}", b.summary());
  }
  

How to use Result step by step

  1. Write a function that returns Result.
  2. Use Ok(value) for success.
  3. Use Err(error) for failure.
  4. Call the function and use match to handle both cases.
  5. Or use ? to propagate the error.

Example:

  fn parse_age(s: &str) -> Result {
      match s.parse::() {
          Ok(age) => Ok(age),
          Err(_) => Err(String::from("Invalid age")),
      }
  }
  

Real-life Examples

  • Bank accounts: Struct with name, number, balance.
  • Traffic lights: Enum with Red, Yellow, Green.
  • Online forms: Option for optional fields.
  • File reading: Result for success or error.
  • Payment systems: Enum with Cash, Card, Transfer.

Nigerian Examples

  • POS transaction: Struct with amount, recipient, status.
  • Market stall: Struct with trader name, goods, prices.
  • Payment method: Enum with Cash, Transfer, Card, USSD.
  • Network status: Option for signal strength.
  • Bank transfer: Result for success or failure.

Fun Examples Children Can Relate To

  • Video game character: Struct with name, health, score.
  • Superpower: Enum with Flying, Invisibility, Strength.
  • Treasure box: Option for gold or empty.
  • Quest result: Result for success or failure.
  • Pet: Struct with name, type, age.

Everyday Examples

  • Contact list: Struct with name, phone, email.
  • Weather: Enum with Sunny, Rainy, Cloudy.
  • Fridge: Option for milk or no milk.
  • Cooking: Result for success or burnt.
  • Shopping list: Struct with item, quantity, price.

Parent Tips

  • Encourage your child to explain their structs out loud.
  • Let them make mistakes. Errors are learning opportunities.
  • Use everyday examples (contact list, weather) to explain structs and enums.
  • Set a small daily coding time. Consistency helps.
  • Celebrate small wins, like creating a working struct.
  • Be patient. Error handling takes time to understand.
  • Ask them to teach you what they learned. Teaching is the best way to learn.
  • Keep it fun. Use games and stories.

Interesting Facts

  • Rust’s Option and Result are inspired by functional programming languages.
  • Rust has no null. Instead, it uses Option.
  • The ? operator is one of Rust’s most loved features.
  • Structs in Rust can have methods, unlike C structs.
  • Enums in Rust can hold data, unlike enums in many other languages.
  • Rust’s compiler forces you to handle every possible error.

Did You Know?

  • Did you know that Rust’s Result is used everywhere in real programs?
  • Did you know that Option prevents the famous “billion-dollar mistake” of null pointers?
  • Did you know that match can destructure structs and enums?
  • Did you know that #[derive(Debug)] lets you print your structs easily?
  • Did you know that the ? operator can be used in functions that return Result?

Remember This

  • Structs group related data.
  • Methods are functions inside impl.
  • Enums represent choices.
  • match handles all enum variants.
  • Option handles missing values.
  • Result handles errors.
  • unwrap is quick but risky.
  • ? propagates errors cleanly.
  • derive adds traits automatically.
  • Rust’s compiler catches many mistakes before running.

Common Mistakes

  • Forgetting to handle None or Err.
  • Using unwrap on a value that might be missing.
  • Forgetting to derive Debug before printing.
  • Missing a field when creating a struct.
  • Using the wrong type in a struct field.
  • Forgetting &self in methods.
  • Not handling all enum variants in match.
  • Ignoring compiler error messages.

Best Practices

  • Use structs for related data.
  • Use enums for choices.
  • Use Option instead of null.
  • Use Result for fallible operations.
  • Avoid unwrap in real programs.
  • Use ? to propagate errors.
  • Derive Debug for easy printing.
  • Keep methods small and focused.
  • Write comments to explain why.
  • Run cargo check often.

Illustrations and Diagrams

Struct and Methods

  struct Student {
      name: String,
      age: u32,
      score: f64,
  }
        |
        V
  impl Student {
      fn show(&self) { ... }
      fn is_pass(&self) -> bool { ... }
  }
        |
        V
  let s = Student { ... };
  s.show();
  s.is_pass();
  

Option Flowchart

  Start
    |
    V
  Value exists?
    |
    +-- Yes --> Some(value)
    |
    +-- No  --> None
    |
    V
  Match on Option
    |
    +-- Some(v) --> Use v
    |
    +-- None    --> Handle missing
  

Result Flowchart

  Start
    |
    V
  Operation succeeded?
    |
    +-- Yes --> Ok(value)
    |
    +-- No  --> Err(error)
    |
    V
  Match on Result
    |
    +-- Ok(v)  --> Use v
    |
    +-- Err(e) --> Handle error
  

Error Propagation with ?

  Function A returns Result
        |
        V
  Calls Function B with ?
        |
        V
  If B returns Ok --> continue
        |
        V
  If B returns Err --> return Err to caller
        |
        V
  Caller handles error
  

Comparison Tables

Struct vs Enum

FeatureStructEnum
PurposeGroup related dataRepresent choices
ExampleStudent { name, age }Grade { A, B, C, F }
FieldsAll fields exist togetherOnly one variant at a time
Use caseData recordsState machines, options

Option vs Result

FeatureOptionResult
PurposeValue may be missingOperation may fail
VariantsSome, NoneOk, Err
Use caseOptional fieldsFile reading, parsing
Error infoNo error detailsContains error details

unwrap vs match vs ?

MethodSafetyWhen to use
unwrap()Risky (panics)Quick tests, prototypes
matchSafeWhen you need custom handling
?SafeWhen you want to propagate errors

Lesson Summaries

Lesson 1: Structs group related data.

Lesson 2: Create instances by filling fields.

Lesson 3: Methods are functions inside impl.

Lesson 4: Enums represent choices.

Lesson 5: Enum variants can hold data.

Lesson 6: match handles all enum variants.

Lesson 7: Option handles missing values.

Lesson 8: Result handles success and failure.

Lesson 9: unwrap and expect are quick but risky.

Lesson 10: The ? operator propagates errors cleanly.

Lesson 11: Combine structs and enums for rich data.

Lesson 12: derive adds traits automatically.

Lesson 13: Common mistakes include unhandled None and missing fields.

Lesson 14: Best practices: use Option, Result, and avoid unwrap.

Lesson 15: Combine structs, enums, methods, and error handling in a student report program.

End-of-Module Summary

Congratulations! You have finished Module Three. You learned how to build your own data types with structs and enums. You learned how to add methods to structs. You learned how to handle missing values with Option and errors with Result. You also learned the ? operator and how to derive traits like Debug. You saw many examples from Nigeria and everyday life. You now know common mistakes and best practices. Most importantly, you can design clean, safe programs that handle errors gracefully. Keep practising, and you will become a great Rust programmer!

Frequently Asked Questions

  1. What is a struct? A custom type that groups related data.
  2. What is an enum? A type that can be one of several variants.
  3. What is a method? A function that belongs to a struct.
  4. What is Option? An enum for values that may be missing: Some or None.
  5. What is Result? An enum for success or failure: Ok or Err.
  6. What is unwrap? A method that extracts a value or panics.
  7. What is the ? operator? It propagates errors cleanly.
  8. What is derive? It automatically adds traits to a struct or enum.
  9. Why does Rust have no null? Because Option handles missing values safely.
  10. How do I handle all enum variants? Use match.

Matching Exercises

Match the word to its definition.

WordDefinition
1. StructA. A type that can be one of several variants.
2. EnumB. Groups related data.
3. MethodC. Handles missing values.
4. OptionD. Handles success or failure.
5. ResultE. A function that belongs to a struct.

Answers: 1-B, 2-A, 3-E, 4-C, 5-D

Scenario-based Exercises

  1. Scenario: You want to store a student’s name, age, and score. What do you use?
    Answer: A struct.
  2. Scenario: You want to represent the days of the week. What do you use?
    Answer: An enum.
  3. Scenario: A user may or may not enter their middle name. What do you use?
    Answer: Option.
  4. Scenario: You are reading a file that might fail. What do you use?
    Answer: Result.
  5. Scenario: You want to print a struct for debugging. What do you add?
    Answer: #[derive(Debug)].

Group Activity

Title: “Build a School Management System”

Instructions: In groups of 3–4, design a Rust program that stores student information. Create a Student struct with name, age, and score. Create a Grade enum with A, B, C, F. Add a method to calculate the grade. Add a method to print the student details. Share your program with the class.

Goal: Practice structs, enums, methods, and match.

Individual Activity

Task: Write a Rust program that defines a Book struct with title, author, and pages. Add a method summary() that returns a string. Create two books and print their summaries.

Hint: Use format! to build the string.

Mini Project

Project: “My Contact List”

Write a Rust program that defines a Contact struct with name, phone, and email (email is Option<String>). Create a few contacts. Add a method to print the contact details. If email is None, print “No email”. Use match to handle the Option.

Example output:

  Name: Ada
  Phone: 08012345678
  Email: ada@example.com
  ---
  Name: Tunde
  Phone: 08087654321
  Email: No email
  

Practical Assignment

Assignment: Create a new Cargo project called bank_account. In main.rs, write a program that:

  1. Defines a BankAccount struct with owner (String) and balance (f64).
  2. Adds methods: deposit(amount) and withdraw(amount) -> Result<(), String>.
  3. withdraw returns Err if there are insufficient funds.
  4. Creates an account, deposits some money, tries to withdraw too much, and prints the result.
  5. Uses match to handle the Result from withdraw.

Submit: Your main.rs file and a screenshot of the program running.

Key Takeaways

  • Structs group related data.
  • Enums represent choices.
  • Methods add behaviour to structs.
  • Option handles missing values.
  • Result handles errors.
  • unwrap is quick but risky.
  • ? propagates errors cleanly.
  • derive adds traits automatically.
  • Rust’s compiler catches many mistakes early.
  • Practice and read error messages carefully.

Classroom Discussion Questions

  1. Why do we need structs?
  2. How are enums different from structs?
  3. Why does Rust have Option instead of null?
  4. What happens if you use unwrap on None?
  5. How does the ? operator help with error handling?
  6. Why is match important with enums?
  7. What traits can you derive for a struct?
  8. How do methods make structs more powerful?
  9. What did Tunde learn from the school register story?
  10. Where do you see structs and enums in Nigeria?

Preparation for Module Four

In Module Four, we will dive deeper into Rust. We will learn about:

  • Collections: vectors, strings, and hash maps.
  • Iterators and closures.
  • Generics and traits.
  • Writing bigger, modular programs.
  • Testing and debugging.
  • Building a complete project.

To prepare, make sure you have completed the practical assignment and can write programs with structs, enums, and error handling. Review your notes on Option and Result. Bring your curiosity!

See you in Module Four!


End of Module Three – Rust Programming for Systems

5

Module Four

Course Conclusion

Congratulations! You have completed all four modules of Rust Programming for Systems. This is a huge achievement. Let us look back at everything you have learned.

What You Learned in Module One

  • What systems programming is and why Rust is special.
  • How to install Rust and Cargo.
  • How to write your first program: Hello, World!
  • Variables, data types, mutability, functions, and comments.
  • How to print output and read input.

What You Learned in Module Two

  • How to make decisions with if, else if, and else.
  • How to use match for pattern matching.
  • How to repeat actions with loop, while, and for.
  • The difference between expressions and statements.
  • The basics of ownership and borrowing.

What You Learned in Module Three

  • How to group data with structs.
  • How to add methods with impl.
  • How to represent choices with enums.
  • How to handle missing values with Option.
  • How to handle errors with Result and the ? operator.

What You Learned in Module Four

  • How to store many values with vectors, strings, and hash maps.
  • How to process collections with iterators and closures.
  • How to write flexible code with generics and traits.
  • How to organise code with modules.
  • How to test and debug your programs.
  • An introduction to lifetimes and smart pointers.

Your Journey

  Module One
      |
      V
  Module Two
      |
      V
  Module Three
      |
      V
  Module Four
      |
      V
  Rust Programmer 🎉
  

What You Can Build Now

With everything you have learned, you can now build:

  • Command-line tools that read input and print results.
  • Games like Guess the Number.
  • School management programs with structs and enums.
  • Market price checkers with hash maps.
  • To-do lists and contact managers.
  • Small systems programs that handle data safely.

Keep Going

Learning Rust does not stop here. To become a great programmer, you should:

  • Practise every day, even for 15 minutes.
  • Read other people’s Rust code.
  • Try to solve small problems on your own.
  • Build your own projects.
  • Read the official Rust book (it is free online).
  • Join a coding club or study group.
  • Never stop asking questions.

Final Words

You started this course not knowing anything about Rust. Now you can write programs that make decisions, repeat actions, store many values, handle errors, and organise code into modules. That is amazing!

Rust is used to build operating systems, web browsers, games, robots, and space satellites. One day, you could build something great with Rust too. Keep learning, keep building, and keep having fun.

Well done, and congratulations on completing the course!


End of Course – Rust Programming for Systems

```

🏆 Get Certified

🔒

Earn this certificate

Every lesson is already free to read. Sign up, pass the exam, and unlock Practice Tools plus a verified certificate with your name on it — ₦4,000/month.

🎓 Sign Up & Unlock for ₦4,000/month
🛠️ Practice Tools
Hands-on simulators & labs - subscription required.
→
🎯 Internship Tasks
Real-world tasks to build your portfolio - try them free for 7 days, no card required.
→