Rust: Variables, Mutability, Immutability and Functions

Rust

  • Systems programming language focused on safety and speed.

  • Developed by Mozilla Research.

  • Key features:

    • Zero-cost abstractions

    • Memory safety without garbage collection

    • Ownership system for manual memory management

    • Statically typed

Variables

  • Used to store data in memory.

  • Immutable by default.

  • Immutability: Value cannot be changed after assignment.

  • To make a variable mutable, use the mut keyword.

Immutability

  • Example:

    let x = 5; // x is immutable
    x = 6;      // Error!
    
  • Immutability prevents accidental changes.

Mutability

  • Example:

    let mut y = 5;
    y = 6; // y is now mutable
    
  • Compiler infers data type upon initialization; manual annotation may be needed.

Constants

  • Defined using the const keyword.

  • Must be set to a constant expression.

  • Valid for the entire program duration.

  • Data type must be annotated.

  • Example:

    const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
    

Variable Shadowing

  • Allows re-declaring a variable with the same name.

  • Creates a new variable instead of mutating the existing one.

  • Can change data types during shadowing.

  • Example:

    let spaces = "  ";
    let spaces = spaces.len(); // spaces is now a number
    

Scalar Types

  • Integers, floating-point numbers, booleans, characters.

  • Signed integers: -(2^{n-1}) to 2^{n-1} - 1

  • Unsigned integers: 0 to 2^n - 1

Integer Types

  • i8, i16, i32, i64, i128, isize (signed)

  • u8, u16, u32, u64, u128, usize (unsigned)

Integer Literals

  • Decimal: 100_000

  • Hex: 0xff

  • Octal: 0o77

  • Binary: 0b1111_0000

  • Byte (u8 only): b'A'

Compound Data Types

Tuples

  • Fixed-size collection of different types.

  • Created using parentheses ().

  • Access elements using 0-based indexing.

    let person: (i32, f64, char) = (25, 6.2, 'A');
    let age = person.0;
    
  • Unit tuple () has special uses.

Arrays

  • Fixed-size collection of the same type.

  • Stored in contiguous memory.

  • Access elements using 0-based indexing.

    let numbers: [i32; 5] = [1, 2, 3, 4, 5];
    let first = numbers[0];
    

Basic Input and Output

  • Example:

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

Expressions and Return Values

  • The return value of a function is the value of the final expression.

  • Returning without the return keyword

    fn five() -> i32 {
        5
    }
    

Functions

  • Type-safe and expressive

  • Example:

    fn plus_one(x: i32) -> i32 {
        x + 1
    }
    

Parameters

fn print_name(name: &str) {
    println!("Hello, {}!", name);
}

Control Flow

If statement

if value.len() == 1 {
    println!("everything okay!");
} else {
    println!("too long!");
}

While loop

let mut remaining_iterations = 10;

while remaining_iterations != 0 {
    println!("{remaining_iterations}!");
    remaining_iterations -= 1;
}

Looping through collections

  • Needs to implement the Iterator trait.

fn print_array(arr: &[i32]) {
    for element in arr {
        println!("The value is: {}", element);
    }
}

Looping through a range

  • .rev() reverses a range.

fn count_down(starting_value: i32) {
    for i in (0..starting_value).rev() {
        println!("{}", i);
    }
}

Infinite loops

  • loop {} loops won’t terminate, break needs to be called explicitly.

fn loop_value() {
    let mut times_looped = 0;

    let times_looped_time_two = loop {
        times_looped += 1;

        if times_looped == 10 {
            break times_looped * 2;
        }
    };

    println!("The result is {times_looped_time_two}");
}