Part 0 · 2 chapters · ~12 min

Basics

Installing with rustup, cargo projects, variables and mutability, scalar and compound types, functions and expressions, control flow and match, structs and enums, Option and Result with the ? operator, modules and crates, and the standard library tour.

1

A first program

code
rustup default stable && cargo new ledger && cd ledger && cargo run

// src/main.rs (compiled and run on this machine: fee(5_000_000) = Ok(25000))
fn fee(amount_kobo: i64) -> Result<i64, String> {
    if amount_kobo <= 0 { return Err(format!("amount must be positive, got {amount_kobo}")); }
    Ok((amount_kobo * 50 / 10_000).max(1_000))          // the last expression is the return value
}

fn main() {
    let amounts = vec![100_000, 5_000_000];             // immutable binding by default
    let mut total = 0;                                  // `mut` to allow change
    for a in &amounts {
        match fee(*a) {
            Ok(f) => { total += f; println!("{a} → {f}"); }
            Err(e) => eprintln!("error: {e}"),
        }
    }
    println!("total fees: {total}");
}
2

Enums, Option, Result and ?

code
enum TransferState { Pending { since: u64 }, Completed { id: String }, Failed { reason: String } }   // data in each variant

fn label(s: &TransferState) -> String {
    match s {                                            // exhaustive: missing a variant is a compile error
        TransferState::Pending { since } => format!("pending since {since}"),
        TransferState::Completed { id } => format!("sent ({id})"),
        TransferState::Failed { reason } => format!("failed: {reason}"),
    }
}

// no null: absence is Option<T>; failure is Result<T, E>; `?` returns early on Err or None
fn total_fee(raw: &str) -> Result<i64, Box<dyn std::error::Error>> {
    let amount: i64 = raw.trim().parse()?;               // ParseIntError converts into the boxed error
    Ok(fee(amount)?)
}

Rust has no null and no exceptions: absence is Option, failure is Result, and the compiler makes you handle both. That is a large part of why Rust programs that compile tend to work.