Variables, Shadowing, and Constants in Rust

Variables, Shadowing, and Constants in Rust

hands-on examples to understand basic concepts in Rust

ยท

5 min read

Understanding Variables in Rust

Rust is a statically and strongly typed language. This means that the compiler must know the type of all variables at compile time. The compiler can usually infer what type we want to use based on the value and how we use it. In cases when many types are possible, we must add a type annotation.

In this article, we will learn about the following:

  • variables and mutability
  • shadowing
  • constants

If you prefer a video version

Variables and mutability

Let's start with understanding variables and mutability.

Let's declare a variable and print it:

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

Here, we are using string interpolation to print the value of x. The curly braces are placeholders for the value of x. The value of x is then passed as an argument to println!().

You should see the following output:

Variables in Rust - Rust programming tutorial

This is an implicit declaration of type, but at compile time, Rust infers the type of x to be i32. This is because we assigned the value 3 to x, and integer literals default to i32 unless otherwise specified.

If you want to declare the variable type explicitly, you can use a type annotation, which is the colon (:) followed by a type name.

Let's try something that seems we can do but we actually can't:

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

    x = 6;
    println!("x is {}", x);
}

In Rust, variables are immutable by default. This means that once we assign a value to a variable, we can't change it. If we try to change the value of a variable, we get an error:

Variables in Rust - Rust programming tutorial

the mut keyword

If we want to change a variable's value, we must declare it as mutable. We do this by adding the mut keyword before the variable name, as shown here:

fn main() {
    let mut x = 5;
    println!("x is {}", x);

    x = 6;
    println!("x is {}", x);
}

Now we can change the value of x without getting an error.

Shadowing

Now, let's see the concept of shadowing.

We can change the value of an immutable variable by shadowing it. Shadowing is when we declare a new variable with the same name as a previous variable. The new variable shadows the previous variable, and we can assign a new value to the new variable while the old variable remains unchanged.

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

    let x = 6;
    println!("x is {}", x);
}

You might think that we would get an error here, but we don't. This is because we are declaring a new variable, not changing the value of the old one. The old variable is still there, but the new variable shadows it. We can't use the old variable anymore, but we can use the new one.

Variables in Rust - Rust programming tutorial

I can even use the previous variable's value to initialize the new variable:

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

    let x = x + 2;
    println!("x is {}", x);
}

Variables in Rust - Rust programming tutorial

Name shadowing in a different scope

Name shadowing is when we declare a new variable with the same name as a previous variable. The new variable shadows the previous variable, and we can assign a new value to the new variable while the old variable remains unchanged.

Let's see an example:

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

    {
        let x = 8;
        println!("x is {}", x);
    }

    let x = x + 2;
    println!("x is {}", x);
}

Variables in Rust - Rust programming tutorial

Changing the type

When you use shadowing, you can change the type of a variable. This is because you are declaring a new variable, not changing the value of the old one.

You can use it to change the type of a variable:

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

    let x = "hello world!";
    println!("x is {}", x);
}

Variables in Rust - Rust programming tutorial

But you can't change the type of a variable without shadowing it:

fn main() {
    let mut x = 5;
    println!("x is {}", x);

    x = "hello world!";
    println!("x is {}", x);
}

We will get an error.

Variables in Rust - Rust programming tutorial

This means that if we use shadowing, we can change the type, but if a variable is mutable, we can't change the type without shadowing it.

Constants Example

Constants are variables that are immutable and have a fixed value.

They are declared using the `const`` keyword. They must be annotated with a type, and they can only be set to a constant expression, not the result of a function call or any other value that could only be computed at runtime.

fn main() {
    const MAX_LEVEL:i32 = 100_000;
    println!("The maximum level is: {}", MAX_LEVEL);
}

Recapt for constants:

  • you must declare the type of the value
  • you must assign a value to the constant on the declaration
  • you cannot redefine or mutate a constant (shadowing doesn't work, can't use mut keyword, can't reassign)

This ends the article.

I hope you enjoyed it and learned something new. If you have any questions, feel free to leave a comment below.

If you prefer a video version

ALL the links here: francescociulla.com

Did you find this article valuable?

Support Francesco Ciulla by becoming a sponsor. Any amount is appreciated!