IS4010: AI-Enhanced Application Development

Week 09: Welcome to Rust

Brandon M. Greenwell

Session 1: Why Rust?

Housekeeping: midterm project

  • Reminder: Your midterm project is due this Sunday at 11:59 PM!
  • Make sure you’ve tested your code locally and pushed all changes to GitHub
  • The automated grading system will run on Monday morning
  • If you have questions, reach out on Teams before Sunday

Welcome to a new frontier

  • For the next few weeks, we are shifting from Python to our second language, Rust
  • Rust is a modern, compiled language focused on three primary goals: performance, reliability, and safety
  • It has a steeper learning curve than Python, but it gives us the power to write incredibly fast and memory-efficient code, which is essential for systems programming, game development, and high-performance computing
  • Created by Graydon Hoare at Mozilla Research in 2006, first stable release in 2015

Why Rust matters in 2025

Compiled vs. interpreted languages

  • Python is an interpreted language. An interpreter reads and executes your code line by line. This makes it flexible and easy to use, but it can be slower
  • Rust is a compiled language. A compiler translates your entire program into machine code—the raw instructions the computer’s CPU understands—before you run it
  • This ahead-of-time compilation is a major reason for Rust’s high performance. It catches errors early and optimizes the code for speed
  • Bonus: Compiled Rust programs don’t need a runtime or interpreter installed to run

Meet cargo, your Rust build tool

  • cargo is Rust’s official build system and package manager, and it’s one of the language’s best features
  • It handles creating new projects, compiling your code, running your application, and managing external libraries (called “crates” in Rust)
  • Think of it as Python’s pip + pytest + black + mypy all rolled into one amazing tool!
  • Cargo is why Rust development feels so smooth and professional

Essential Cargo commands

Project management: - cargo new project_name: creates a new “Hello, world!” project - cargo init: initialize Cargo in an existing directory

Building and running: - cargo build: compiles your code (debug mode) - cargo run: compiles and runs in one command - cargo build --release: optimized production build

Development workflow: - cargo check: fast compile check (no executable) - cargo test: run all tests - cargo clean: delete build artifacts

Cargo’s secret weapons: clippy and rustfmt

cargo clippy - your personal Rust mentor: - Catches common mistakes and suggests better approaches - Over 500 lints for code quality, performance, and style - Like having a senior Rust developer review your code - Example: “you can simplify this code” or “this might panic”

cargo fmt - automatic code formatting: - Formats your code to match Rust community style - No more debates about spacing, indentation, or style - Run before every commit - keeps code consistent - Like Python’s black formatter

Your Rust development workflow

This is what professional Rust developers do:

  1. Write code in your editor
  2. cargo check - fast compilation check while coding
  3. cargo clippy - catch issues and learn better patterns
  4. cargo test - verify your code works correctly
  5. cargo fmt - format code before committing
  6. cargo run - try out your program

Pro tip: Run cargo check constantly. It’s 10x faster than cargo build!

Rust Playground: try before you install

  • Before installing anything, you can experiment with Rust in your browser at play.rust-lang.org
  • The Rust Playground lets you write, compile, and run Rust code instantly
  • Perfect for testing small examples, sharing code snippets, and learning syntax
  • Every code example in these slides has a clickable Playground link - try them all!
  • You’ll use the Playground extensively in this week’s practice exercises

🎮 Live Demo: Your first Rust code!

👉 Everyone open this link NOW: play.rust-lang.org

Follow along:

  1. Click “Run” - see “Hello, world!” in the output
  2. Edit the message - change it to your name
  3. Click “Run” again - see your personalized greeting!
  4. Click “Share” - get a permanent link to save your work

🎯 Challenge: Can you make it print TWO lines with different messages?

Hello, Rust!

  • When you run cargo new hello_rust, it creates a simple project structure for you
  • The main source code lives in src/main.rs
  • The fn main() block is the entry point for every Rust executable
  • println! is a macro (not a function, note the !) that prints text to the console
// Inside src/main.rs
fn main() {
    println!("Hello, Rust!");
}

🎮 Try it yourself: ▶ Run in Rust Playground

Your turn: Modify the message and add a second println! line!

Session 2: Rust basics

Variables and mutability

  • We declare variables using the let keyword
  • A core concept in Rust is that variables are immutable by default. Once a value is bound to a name, you can’t change it. This helps us write safer code
  • To make a variable mutable, you must explicitly use the let mut keyword
  • This is the opposite of Python, where everything is mutable by default!
let x = 5;        // immutable
let mut y = 10;   // mutable
y = 15;           // this is allowed
// x = 6;         // this would cause a compiler error!

🎮 Try it yourself: ▶ Experiment in Playground

🎯 Challenge: Uncomment the x = 6; line. What error do you get? Read it carefully!

Scalar data types

  • Rust is a statically typed language, meaning the type of every variable must be known at compile time
  • It has four primary scalar (single value) types:
    • Integers: signed (i32, i64) or unsigned (u8, u32). The number is the bits of space it takes up. i32 is the default
    • Floating-point numbers: f32 (single-precision) and f64 (double-precision). f64 is the default
    • Booleans: bool with values true or false
    • Characters: char, for a single Unicode character, denoted with single quotes

Compound data types

  • Rust has two primary built-in compound types for grouping multiple values
  • The tuple is a fixed-size collection of values of different types. Once declared, a tuple’s size cannot change
  • The array is a fixed-size collection where every element must have the same type
  • For dynamic sizing, we’ll learn about Vectors and HashMaps later
// A tuple with different types
let my_tuple: (i32, f64, u8) = (500, 6.4, 1);

// An array with five elements of the same type
let my_array: [i32; 5] = [1, 2, 3, 4, 5];

🎮 Try it yourself: ▶ Run in Playground

🎯 Challenge: Try accessing my_tuple.0 and my_array[0]. What do you get?

Functions in Rust

  • We define functions using the fn keyword
  • You must declare the type of each function parameter
  • If the function returns a value, you must declare its type after an arrow ->
  • The final expression in a function is automatically returned; you don’t need the return keyword if it’s at the end
  • This is called an expression-based language - expressions return values, statements don’t
fn add(num1: i32, num2: i32) -> i32 {
    // No semicolon means this is an expression, and it's returned
    num1 + num2
}

🎮 Try it yourself: ▶ Run in Playground

🎯 Challenge: Add a semicolon after num1 + num2. What error appears? Why?

How do we know our code works?

  • In the Python section, we used the pytest library to run our tests
  • Rust has a powerful testing framework built directly into the language and its tooling
  • We can write tests for our code and run them from the command line using a simple, built-in command: cargo test
  • No need to install separate testing libraries - testing is first-class in Rust!

The anatomy of a Rust test

  • Tests are just functions marked with a #[test] attribute
  • By convention, they are placed in a special module named tests inside the same file as the code they are testing
  • The #[cfg(test)] attribute tells Rust to only compile and run this code when we execute cargo test
fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*; // Brings `add_two` into scope

    #[test]
    fn it_adds_two() {
        assert_eq!(add_two(2), 4);
    }
}

Assertion macros

  • How do we actually check if our code is correct inside a test? We use assertion macros
  • A test passes if the function completes without the macro “panicking” (crashing)
  • The most common macros are:

Our workflow for Rust labs

  • For the Rust labs, we will provide the test suite for you
  • Your workflow should be:
    1. Write your solution code in src/main.rs
    2. Append our provided test module to the bottom of that file
    3. Run cargo test in your terminal to check your work locally
    4. Once all tests pass, commit and push your code to GitHub
  • This gives you instant feedback without having to wait for the CI/CD pipeline
  • Green tests = you’re ready to submit! 🎉

Introducing Lab 09

  • This week’s lab is your first hands-on introduction to Rust
  • You’ll install the Rust toolchain using rustup
  • Create your first Cargo project
  • Practice with variables, data types, and functions
  • Write and run tests with cargo test
  • Full instructions are in labs/lab09/README.md
  • Don’t forget the Rust Playground exercises for extra practice!

Resources for learning Rust