rust

What exactly is the scope of the use statement in Rust, and why?


How come the scope of a use statement is so different from the scope of say a variable in Rust? Specifically, how come a use statement is not valid anymore inside a new module? Consider this code, adapted from https://doc.rust-lang.org/book/ch07-04-bringing-paths-into-scope-with-the-use-keyword.html

mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

use crate::front_of_house::hosting;
fn foo() { }

mod customer {
    pub fn eat_at_restaurant() {
        hosting::add_to_waitlist(); // doesn't work, hosting is not in scope
        foo(); // works, foo is still in scope EDIT: I was wrong about this, this does not compile
    }
}

The book says about this block of code:

Note that use only creates the shortcut for the particular scope in which the use occurs. Listing 7-12 moves the eat_at_restaurant function into a new child module named customer, which is then a different scope than the use statement, so the function body won’t compile.

What exactly is the definition of scope here? When introducing a new scope with curly braces, that does not make use statements go out of scope. Neither do function definitions.

I understand that this only happens when defining a new module. 1) Why? 2) Where are these rules formally stated?

EDIT: I was wrong in this question, scope of function definitions and use behave almost exactly the same way, see accepted answer.


Solution

  • What makes you think foo would be in scope? This code doesn't compile in any Rust version or edition:

    fn foo() { }
    
    mod customer {
        pub fn eat_at_restaurant() {
            foo(); // error[E0425]: cannot find function `foo` in this scope
        }
    }
    

    What exactly is the definition of scope here? When introducing a new scope with curly braces, that does not make use statements go out of scope. Neither do function definitions.

    In general, identifiers in a parent scope are in scope in any child scope:

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

    However, there are exceptions, including:

    fn main() {
        let x = 5;
        fn print() {
            println!("{x}"); // error[E0434]: can't capture dynamic environment in a fn item
        }
    }
    
    fn main() {
        const X: i32 = 5;
        mod print {
            const Y : i32 = X; // error[E0425]: cannot find value `X` in this scope
        }
    }
    

    It may be useful to imagine every mod foo { ... } as a separate file, containing ... and included by mod foo;, which is actually an equivalent way of declaring a module.

    Where are these rules formally stated?

    Here is the formal documentation of "scope" and here are some extra examples of "scope" in general and "scope" for variables. If you're new to Rust, the Rust book and examples are probably a better introduction than the formal documentation.

    Note that there are some inconsistencies between variable and use scope, such as the fact that use statements can be placed after the symbol they import is used. In the following code, there is only one scope issue, related to the variable:

    fn main() {
        let _y = x; // error[E0425]: cannot find value `x` in this scope
    
        let x = NonZeroU8::new(0); // totally fine!
        
        use std::num::NonZeroU8;
    }