Variables

Like most other programming languages, Rust allows you to declare variables with a specific data type. You use the let keyword to indicate that you are declaring a new variable.

Variable Mutability

By default, variables in Rust are immutable, meaning that once they've been initialized, the values cannot be changed.

#![allow(unused)]
fn main() {
let name = "Trevor";
name = "Trevor";       // This is NOT allowed, and results in a compiler error.
}

If you need to change the value of a variable, after it has been initialized, you can use the mut keyword before the variable name.

#![allow(unused)]
fn main() {
let mut name = "Trevor";
name = "Joe";
}

These examples only show mutating values of a primitive data type. For more complex data structures, using the mut keyword may be necessary to allow alteration of the object's internal state.

Specify Data Type

When you declare a Rust variable, you can specify its data type, directly following the variable name. For numeric types, you can specify the size of the type, such as u8 (unsigned 8-bit integer) or i128 (signed 128-bit integer).

Numeric Values

#![allow(unused)]
fn main() {
let age = 30u8;                  // Define an unsigned 8-bit integer
let number_of_ducklings = 8u128; // Define an unsigned 128-bit integer (largest possible size)

let cost: f32 = 30.28; // Define a 32-bit floating point value
let cost: f64 = 80.99; // Define a 64-bit floating point value

let item_price = 73.09f32; // Define a 32-bit floating point value
let item_price = 91.12f64; // Define a 64-bit floating point value
}

Variable Shadowing

Although some other languages don't allow you to re-declare the same variable, Rust does allow this. We call this behavior variable "shadowing." You can use the same variable name that has already been declared in the current scope to declare a new variable with the let keyword. When the shadow variable goes out of scope, the variable reverts to its previous value. Variable shadowing allows you to assign different data types to the same variable name (ie. &str and u8).

Here's a simple example on the Rust playground.

#[tokio::main]
async fn main() {
    println!("How does Rust variable shadowing work?");
    let person = "Trevor";
    
    // Let's shadow the variable in a child block / scope
    {
      println!("The person variable is: {0}", person);
      
      // This shadowed variable goes out of scope
      // at the end of the block, and reverts to its previous value
      let person = 30u8; 
      println!("Now we change person variable to: {0}", person);
      
      // Now we will nest another child block inside the parent block
      {
          let person = 1.18992152f32;
          println!("Now person has a floating point value: {0}", person);
      } // The f32 value goes out of scope here
    } // The u8 value goes out of scope here
    println!("Now we're back to: {0}", person);
}

The output of this snippet should look similar to this:

How does Rust variable shadowing work?
The person variable is: Trevor
Now we change person variable to: 30
Now person has a floating point value: 1.1899215
Now we're back to: Trevor