Rust Fundamentals: Ownership, Errors and Fearless Concurrency · Rust Basics and Ownership

Types, Functions and Control Flow

Rust's number, boolean, char, tuple and array types, functions with typed parameters, expressions that return values, and if, loop, while, for and ranges.

Create a free account to save this page, take notes and track your progress. Sign in

What you'll build

A grade calculator: a function that turns a score into a letter, another that returns several values as a tuple, and loops that summarise a class's results.

The idea

Scalar types: integers (i32 default, u8, u64, usize for sizes and indexes…), floats (f64 default), bool, and char (a Unicode character in single quotes). Compound types: tuples (i32, f64, &str) and fixed-size arrays [i32; 5].

Functions declare parameter types and the return type after ->. The last expression without a semicolon is the return value:

fn double(x: i32) -> i32 {
    x * 2        // no semicolon: this is the value returned
}

That's because Rust is expression-based: if, match and blocks produce values, so let label = if score >= 50 { "pass" } else { "fail" }; works.

Loops: loop (forever, until break, which can return a value), while condition, and for item in collection. Ranges: 1..5 (1 to 4), 1..=5 (1 to 5), .rev() to go backwards.

The code

Grades with functions, tuples, expressions and loops
fn letter(score: u32) -> char {
    if score >= 90 {
        'A'
    } else if score >= 80 {
        'B'
    } else if score >= 70 {
        'C'
    } else {
        'F'
    }
}

fn stats(scores: &[u32]) -> (u32, u32, f64) {
    let mut min = u32::MAX;
    let mut max = 0;
    let mut sum = 0;
    for &s in scores {
        min = min.min(s);
        max = max.max(s);
        sum += s;
    }
    (min, max, sum as f64 / scores.len() as f64) // a tuple: three values at once
}

fn main() {
    let names = ["Ana", "Ben", "Cleo", "Dev"];
    let scores = [92, 78, 85, 64];

    for i in 0..names.len() {
        let result = if scores[i] >= 70 { "pass" } else { "retake" }; // if is an expression
        println!("{:<5} {:>3} {} {}", names[i], scores[i], letter(scores[i]), result);
    }

    let (min, max, avg) = stats(&scores); // destructure the tuple
    println!("min {min}, max {max}, average {avg:.1}");

    let mut attempts = 0;
    let first_a = loop {
        if scores[attempts] >= 90 {
            break names[attempts]; // break can return a value from loop
        }
        attempts += 1;
    };
    println!("first A: {first_a}");

    for n in (1..=3).rev() {
        print!("{n}... ");
    }
    println!("done!");
}

Output

Ana    92 A pass
Ben    78 C pass
Cleo   85 B pass
Dev    64 F retake
min 64, max 92, average 79.8
first A: Ana
3... 2... 1... done!

Run this on your computer — see “Get Started” for setup.

Common mistakes

  • Adding a semicolon to the return expression. x * 2; becomes a statement, the function returns (), and the compiler reports "mismatched types".
  • Out-of-bounds indexing. scores[10] compiles but panics at runtime; prefer iterating or .get(i).
  • Integer overflow surprises. In debug builds overflow panics; use wider types or checked_add when values can grow.
  • Using i32 for lengths and indexes. Rust uses usize there; convert with as when needed.
  • 1..5 vs 1..=5. The first excludes 5.

Key points

  • Integers, floats, bool, char; tuples and arrays for grouping.
  • Functions declare types; the last expression (no semicolon) is returned.
  • if, blocks and loop are expressions that produce values.
  • for x in collection, ranges a..b and a..=b, .rev().

Further reading: Data types, Functions, Control flow.

Practice questions

Why does `fn double(x: i32) -> i32 { x * 2; }` fail to compile?

Answer

The semicolon turns the expression into a statement, so the block's value is the unit type (), which doesn't match the declared return type i32. Remove the semicolon (or use return x * 2;).

What does it mean that Rust is expression-based?

Answer

Most constructs produce values: if/else, match, blocks and loop (via break value) can be used on the right side of let or as a function's final expression.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?