Skip to main content
  1. Posts/

Rust shadowing

·3 mins
Rust shadowing is a feature that you don’t know you need until you need it.

What’s Shadowing? #

Shadowing in Rust is like variables reinvent themselves, change their type, value, or even purpose, without changing their name. Have you ever seen those crazy names like tempValue, tempValue2, and tempValueFinalFinalV2 (super bad names btw)? Rust, as we know, always cares about good coding and says, hey! let’s just reuse the same name!

In most programming languages, once you declare a variable, that’s it, it’s stuck with that name, type, and value until the end of time (or until the function ends, at least). In Rust, however, shadowing lets you take the same variable name and give it a new purpose.

What’s the Point? #

So why does Rust allow this weird thing? It’s all about keeping your code clean and readable. Instead of creating a dozen new variables with slightly different names, you can just keep using the same one, as long as it makes sense contextually. The most important thing is that shadowing doesn’t mutate the original variable, it simply hides it under the rug and lets the new version work for a while, let’s see it.

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

    let x = x + 1;  // x is now 6
    println!("The value of x is: {}", x);

    let x = "Hello, shadowing!";  // x is now a string
    println!("The value of x is: {}", x);
}

I know, I know… you may be wondering what’s the use case, here are a few:

Refining the value of a variable #

This example could be a one liner but it’s just to get the idea.

fn process_input(input: &str) {
    let input = input.trim();  // First, clean up any extra whitespace
    let input = input.to_lowercase();  // Then, normalize the case
    let input = input.replace(" ", "_");  // Finally, replace spaces with underscores

    println!("Processed input: {}", input);
}

Avoiding unnecessary immutability #

You can also avoid mutability with shadowing. Instead of declaring mut x and changing its value, you can shadow the original immutable x with a new value.

fn double_value(x: i32) -> i32 {
    let x = x * 2;  // Reassign the value without needing mutability
    x
}

Rehuse same name in a different scope #

Shadowing allows you to redefine a variable within other scope (code block).

fn main() {
    let config = get_config();  // Initial configuration, maybe a complex struct
    {
        let config = config.simplify();  // Simplified version for this block only
        process_with_simple_config(config);
    }
    // The original `config` is still available here
    process_with_full_config(config);
}

Conclusions #

In Rust, shadowing is part of its design philosophy. You can reuse a variable name in the same scope, and each new declaration of that name creates a completely new binding. Importantly, shadowing doesn’t mutate the original variable; it just hides it. This approach allows you to change the variable’s type or value in a controlled and safe way.