Variables and Mutability

Variables are immutable by default in Rust. This design choice enforces memory safety and prevents data races in concurrent contexts.

fn main() {
    let x = 5;
    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");
}

This produces a compile-time error:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
error[E0384]: cannot assign twice to immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         - first assignment to `x`
3 |     println!("The value of x is: {x}");
4 |     x = 6;
  |     ^^^^^ cannot assign twice to immutable variable
  |
help: consider making this binding mutable
  |
2 |     let mut x = 5;
  |         +++

For more information about this error, try `rustc --explain E0384`.
error: could not compile `variables` (bin "variables") due to 1 previous error

To allow mutation, use the mut keyword:

fn main() {
    let mut x = 5;
    println!("The value of x is: {x}");
    x = 6;
    println!("The value of x is: {x}");
}

Constants

Constants differ from immutable variables in several ways:

  • Always immutable (no mut allowed)
  • Declared with const keyword
  • Type annotation required
  • Must be set to compile-time constant expressions
  • Can be declared in any scope, including global
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;

Constants use SCREAMING_SNAKE_CASE by convention and are valid for the entire program duration within their scope.

Shadowing

Rust allows variable shadowing - declaring a new variable with the same name:

fn main() {
    let x = 5;

    let x = x + 1;

    {
        let x = x * 2;
        println!("The value of x in the inner scope is: {x}");
    }

    println!("The value of x is: {x}");
}

Output:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.31s
     Running `target/debug/variables`
The value of x in the inner scope is: 12
The value of x is: 6

Shadowing differs from mutation:

  • Creates a new variable (enables type changes)
  • Requires let keyword
  • Variable remains immutable after transformations
fn main() {
    let spaces = "   ";
    let spaces = spaces.len();
}

This is invalid with mut:

fn main() {
    let mut spaces = "   ";
    spaces = spaces.len();
}

Error:

$ cargo run
   Compiling variables v0.1.0 (file:///projects/variables)
error[E0308]: mismatched types
 --> src/main.rs:3:14
  |
2 |     let mut spaces = "   ";
  |                      ----- expected due to this value
3 |     spaces = spaces.len();
  |              ^^^^^^^^^^^^ expected `&str`, found `usize`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `variables` (bin "variables") due to 1 previous error