Module: Variables and Data

Variables

Rust Variables

Variables in Rust are used to store data. Rust's approach to variables is a bit different than many other languages, emphasizing safety and immutability by default. Here's a breakdown:

1. Declaration and Initialization

  • let keyword: Used to declare a variable.
  • Immutability by default: Variables declared with let are immutable by default. This means their value cannot be changed after initialization.
  • Type Inference: Rust often infers the type of a variable based on its initial value. You don't always need to explicitly specify the type.
  • Explicit Type Annotation: You can explicitly specify the type using a colon (:) after the variable name.
fn main() {
    // Type inference: Rust infers 'x' is an i32 (32-bit integer)
    let x = 5;

    // Explicit type annotation: 'y' is explicitly declared as a f64 (64-bit float)
    let y: f64 = 3.14159;

    println!("x = {}, y = {}", x, y);

    // Attempting to modify x will result in a compile-time error:
    // x = 6; // Error: cannot assign twice to immutable variable `x`
}

2. Mutable Variables

  • mut keyword: To make a variable mutable (changeable), you need to use the mut keyword before the variable name.
fn main() {
    let mut z = 10;
    println!("z = {}", z);

    z = 20; // This is allowed because 'z' is mutable
    println!("z = {}", z);
}

3. Shadowing

  • Declaring a new variable with the same name: You can declare a new variable with the same name as an existing variable. This is called shadowing.
  • New variable, different type: The new variable effectively hides the previous one. The shadowed variable can even be of a different type.
  • Scope: Shadowing happens within the same scope.
fn main() {
    let x = 5;
    println!("The value of x is: {}", x);

    let x = x + 1; // Shadowing: a new variable 'x' is created
    println!("The value of x is: {}", x);

    let x = "hello"; // Shadowing again: 'x' now holds a string
    println!("The value of x is: {}", x);
}

4. Constants

  • const keyword: Used to declare constants.
  • Must be explicitly typed: Constants must have their type explicitly specified.
  • Compile-time evaluation: Constants are evaluated at compile time.
  • Immutable: Constants are always immutable.
  • Naming convention: Constants are typically named using UPPER_SNAKE_CASE.
fn main() {
    const MAX_POINTS: u32 = 100_000; // u32 is an unsigned 32-bit integer
    println!("The maximum number of points is: {}", MAX_POINTS);
}

5. Variable Scope

  • Block scope: Variables are scoped to the block of code in which they are defined (e.g., within a function, loop, or if statement).
  • Last expression in a block: The last expression in a block is implicitly returned (if the block is part of a function).
fn main() {
    let a = 10;

    {
        let b = 5;
        println!("Inside the block: a = {}, b = {}", a, b);
    }

    // println!("Outside the block: a = {}, b = {}", a, b); // Error: b is not in scope

    println!("Outside the block: a = {}", a);
}

Key Takeaways:

  • Rust prioritizes immutability by default, promoting safer code.
  • Use mut to create mutable variables.
  • Shadowing allows you to reuse variable names, potentially with different types.
  • const defines compile-time constants.
  • Understand variable scope to avoid errors.

This covers the fundamental concepts of variables in Rust. Understanding these concepts is crucial for writing correct and efficient Rust code. Remember to consult the official Rust documentation for more in-depth information: https://doc.rust-lang.org/book/ch03-02-variables.html