Search code examples
variablesrustglobal-variables

Confusing global constant variable in rust


I did many experiment with rust global variables i can't understand; why is this happening

#![allow(unused)]

const I:i32 = 10;

fn main() {
    let gi = I;
    println!("{}", gi);
    const I:i32 = 20;
    println!("{}", gi);
}

when i do this i expect this output

10
10

but the output i get is this

20
20

I have not touched gi but it still changes when i change global variable I also if i change I after printing gi once i do not understand why the first output also changes that breaks the flow of control


Solution

  • It is not a matter of reassigning something supposed to be const, but rather a matter of shadowing a constant with another with the same name.

    Your first constant has a global scope but your second one exists in the scope of the main() function. In this function, if we refer to I it will be found in the smaller enclosing scope, which is the main() function.

    In the modified example below, I introduce a new block in order to illustrate this. From the point of view of gi, I is found at the global scope, but once inside the artificial block I refers to its second definition (in this block).

    The confusing part is that the inner constant is found even if it is defined after the statement referring to it. If it was a variable, it would not be correct, but because it is a constant, the order is not important (this is like a lexical substitution). It would be the same situation if the top I appeared below the main() function: it would exist in the global scope anyway.

    const I: i32 = 10;
    
    fn main() {
        let gi = I;
        println!("before block: gi={}  I={}", gi, I);
        {
            println!("enter block: gi={}  I={}", gi, I);
            const I: i32 = 20;
            println!("leave block: gi={}  I={}", gi, I);
        }
        println!("after block: gi={}  I={}", gi, I);
    }
    /*
    before block: gi=10  I=10
    enter block: gi=10  I=20
    leave block: gi=10  I=20
    after block: gi=10  I=10
    */