Home Rust Tutorial: Variables in Rust Programming Language

Tutorial: Variables in Rust Programming Language

Variables are fundamental to programming, and Rust offers a unique way of handling them.

Rust emphasizes safety and immutability by default, which means variables are immutable unless explicitly stated otherwise.

This tutorial will cover:

1. Declaring Variables

In Rust, variables are declared using the let keyword. By default, variables are immutable, meaning their value cannot be changed once assigned.

Example: Immutable Variables

fn main() {
    let x = 10;  // Immutable variable
    println!("x = {}", x);

    // Uncommenting the next line will cause a compile error
    // x = 20; // Error: cannot assign twice to an immutable variable
}

2. Mutable Variables

To create a variable whose value can change, use the mut keyword.

Example: Mutable Variables

fn main() {
    let mut y = 5;  // Mutable variable
    println!("y = {}", y);

    y = 10;  // Changing the value
    println!("y = {}", y);
}

3. Shadowing Variables

Rust allows shadowing, where a variable with the same name can be declared again, effectively replacing the previous variable. This is different from mutability as the type or value can change in each shadowing.

Example: Variable Shadowing

fn main() {
    let z = 5;
    println!("z = {}", z);

    let z = z + 1;  // Shadowing: `z` is redefined
    println!("z = {}", z);

    let z = "Rust";  // Shadowing with a different type
    println!("z = {}", z);
}

4. Constants

Constants are similar to variables but have the following restrictions:

  • Declared using the const keyword.
  • Always immutable (cannot use mut).
  • Must have a type annotation.
  • Must be initialized with a constant expression.

Example: Constants

fn main() {
    const PI: f64 = 3.14159;
    const MAX_SCORE: u32 = 100;

    println!("PI = {}", PI);
    println!("Max score = {}", MAX_SCORE);
}

5. Data Types in Variables

5.1 Explicit Type Annotations

You can specify the type of a variable explicitly.

fn main() {
    let a: i32 = 10;    // 32-bit signed integer
    let b: f64 = 3.14;  // 64-bit floating point
    let c: bool = true; // Boolean
    let d: char = 'R';  // Character

    println!("a = {}, b = {}, c = {}, d = {}", a, b, c, d);
}

5.2 Type Inference

Rust can infer the type of variables based on their assigned value.

fn main() {
    let x = 42;  // Inferred as i32
    let y = 2.718;  // Inferred as f64

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

6. Default Type Inference

Rust assigns default types when no type is specified:

  • Integer literals default to i32.
  • Floating-point literals default to f64.

Example: Default Types

fn main() {
    let num = 100;      // Defaults to i32
    let decimal = 2.5;  // Defaults to f64

    println!("num = {}, decimal = {}", num, decimal);
}

7. Scope and Lifetime

Variables in Rust have a scope that determines where they are accessible. A variable is dropped (deallocated) when it goes out of scope.

Example: Variable Scope

fn main() {
    {
        let inner = "This is inner scope";
        println!("{}", inner);
    }
    // println!("{}", inner); // Error: `inner` is not accessible here
}

8. Practical Examples

8.1 Swapping Variables

You can swap the values of two variables using tuple destructuring.

fn main() {
    let mut a = 10;
    let mut b = 20;

    println!("Before swap: a = {}, b = {}", a, b);

    // Swap values
    (a, b) = (b, a);

    println!("After swap: a = {}, b = {}", a, b);
}

8.2 Using Shadowing for Transformations

Shadowing is helpful for applying transformations without creating new variable names.

fn main() {
    let price = 100;  // Original price
    let price = price * 2;  // Double the price
    let price = price - 10;  // Apply a discount

    println!("Final price: {}", price);
}

8.3 Working with Mutable Variables

Mutable variables are useful when state needs to change.

fn main() {
    let mut counter = 0;

    for _ in 0..5 {
        counter += 1;  // Increment counter
        println!("Counter: {}", counter);
    }
}

8.4 Combining Constants and Variables

Combine constants and variables for efficient calculations.

fn main() {
    const TAX_RATE: f64 = 0.15;
    let price = 100.0;
    let total = price + (price * TAX_RATE);

    println!("Total price with tax: {:.2}", total);
}

Key Takeaways

  • Variables in Rust are immutable by default, promoting safety and predictability.
  • Use mut to make variables mutable when necessary.
  • Shadowing allows redeclaring variables, enabling transformations and reassignments with flexibility.
  • Constants are immutable, require explicit type annotations, and are evaluated at compile time.

Rust’s variable system, with its emphasis on immutability, helps prevent bugs and encourages good programming practices.

You may also like