0Pricing
Learn Rust Coding · Lesson

Shadowing

Rebinding variables.

Shadowing is a free Learn Rust Coding lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What Is Shadowing?

Shadowing means declaring a new variable with the same name as a previous one. The new binding 'shadows' the old.

You do this by repeating let with the same name.

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

Shadowing Is Not Mutation

Shadowing creates a brand-new variable. This differs from mut, which reuses the same variable.

Because each let is a new binding, the values can even have different types.

fn main() {
    let y = 10;        // immutable
    let y = y + 5;     // new binding, also immutable
    println!("y is {}", y);
}

Changing Types with Shadowing

A powerful use of shadowing is reusing a name while changing its type.

Here a string is parsed into a number under the same name.

fn main() {
    let spaces = "   ";
    let spaces = spaces.len();
    println!("count is {}", spaces);
}

Why mut Cannot Change Type

With mut you can change the value but not the type.

This would fail to compile:

  • let mut spaces = " ";
  • spaces = spaces.len(); — type mismatch error.

Shadowing avoids this because it makes a new variable.

fn main() {
    let mut count = 3;
    count = 4; // ok, same type
    println!("{}", count);
}

Shadowing in Inner Scopes

A variable can be shadowed inside an inner block. When the block ends, the outer binding is visible again.

fn main() {
    let n = 1;
    {
        let n = n * 10;
        println!("inner {}", n);
    }
    println!("outer {}", n);
}

Transforming Step by Step

Shadowing lets you transform a value through several steps while keeping one clear name.

fn main() {
    let input = "42";
    let input: i32 = input.trim().parse().unwrap();
    let input = input * 2;
    println!("result {}", input);
}

Shadowing Keeps Immutability

Each shadowed binding stays immutable. After a transformation you keep the safety of immutability without inventing new names like x2 or x_temp.

fn main() {
    let price = 100;
    let price = price - 20;   // discount applied
    let price = price + 5;    // shipping added
    println!("final price {}", price);
}

Shadowing with Different Logic

You can compute the new value any way you like, including with function calls or expressions.

fn main() {
    let text = "hello";
    let text = text.to_uppercase();
    println!("{}", text);
}

Avoiding Confusion

Shadowing is handy, but overusing it can confuse readers. Use it when each step is a clear transformation of the same concept, not just to recycle names randomly.

fn main() {
    let raw = "  Rust  ";
    let raw = raw.trim();      // clean version
    println!("[{}]", raw);
}

Shadowing vs Reassignment Summary

Two ways to give a name a new value:

  • Shadowing: let x = ...; again — new variable, can change type, stays immutable.
  • Reassignment: x = ...; with mut — same variable, same type required.
fn main() {
    let val = "7";
    let val: i32 = val.parse().unwrap(); // shadow + type change
    let mut val = val;
    val += 1;                            // reassign, same type
    println!("{}", val);
}

A Practical Example

Reading and converting user data is a classic place for shadowing: keep the meaningful name age while the type changes from text to number.

fn main() {
    let age = "25";
    let age: u32 = age.parse().unwrap();
    let age = age + 1; // next birthday
    println!("next year you will be {}", age);
}

Quick Check

Decide what distinguishes shadowing from using mut.

Recap

Shadowing in Rust:

  • Repeat let with the same name to create a new binding.
  • The new binding can have a different type.
  • Each shadowed value remains immutable.
  • It differs from mut, which mutates the same variable and keeps its type.
fn main() {
    let data = "100";
    let data: i32 = data.parse().unwrap();
    let data = data / 4;
    println!("final {}", data);
}

Frequently asked questions

Is the “Shadowing” lesson free?

Yes — the full text of “Shadowing” is free to read here on the web, and the Learn Rust Coding course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.

What will I learn in “Shadowing”?

Rebinding variables. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Learn Rust Coding?

No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Shadowing” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Learn Rust Coding lesson?

Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. let and Mutability
  2. Scalar Types
  3. Compound Types
  4. Shadowing
← Back to Learn Rust Coding