daparic
daparic

Reputation: 4454

Rust shadowed variable type auto-change

I am referring to the type of the guess variable. It seems that the type changes from a String then to an i32 and then back to a String.

use std::{any::Any, io};

fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}

fn main() {
    let mut guess = String::new();

    loop {
        print_type_of(&guess);
        guess.clear();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess: i32 = match guess.trim().parse() {
            Ok(x) => x,
            Err(_) => continue,
        };

        print_type_of(&guess);

        if guess == 69 {
            break;
        }
    }

    println!("{}", guess);
}

I can understand the concept of shadowing in a linear and scoped context. But after the guess has been shadowed and becomes an i32, I am surprised to find that when going back at the top of the loop, it suddenly changes back to a String type!?!?

Upvotes: 0

Views: 121

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 70950

Shadowing does not follow control flow, it is linear with the source code. At the loop entry, you have one guess with type String. When you declare let guess: i32, you introduce a new variable named guess with the type i32. You cannot access the original guess because it is shadowed, but it's still there. We don't "loop again": we just inspect all guess variables in the current scope, and the one you're referring to is the closest one. When you are after the second guess declaration it's it; when you're before it's the first guess. You may find it more natural if you'll think of each variable as having a number attached:

fn main() {
    let mut guess_1 = String::new();

    loop {
        print_type_of(&guess_1);
        guess_1.clear();

        io::stdin()
            .read_line(&mut guess_1)
            .expect("Failed to read line");

        let guess_2: i32 = match guess_1.trim().parse() {
            Ok(x) => x,
            Err(_) => continue,
        };

        print_type_of(&guess_2);

        if guess_2 == 69 {
            break;
        }
    }

    println!("{}", guess_1);
}

Upvotes: 1

Related Questions