Referring to Names in Different Modules - The Rust Programming Language

## Referring to Names in Different Modules

We’ve covered how to call functions defined within a module using the module name as part of the call, as in the call to the `nested_modules` function shown here in Listing 7-7:

Filename: src/main.rs

    pub mod a {
        pub mod series {
            pub mod of {
                pub fn nested_modules() {}
            }
        }
    }

    fn main() {
        a::series::of::nested_modules();
    }

Listing 7-7: Calling a function by fully specifying its enclosing module’s path

As you can see, referring to the fully qualified name can get quite lengthy. Fortunately, Rust has a keyword to make these calls more concise.

### Bringing Names into Scope with the `use` Keyword

Rust’s `use` keyword shortens lengthy function calls by bringing the modules of the function you want to call into scope. Here’s an example of bringing the `a::series::of` module into a binary crate’s root scope:

Filename: src/main.rs

    pub mod a {
        pub mod series {
            pub mod of {
                pub fn nested_modules() {}
            }
        }
    }

    use a::series::of;

    fn main() {
        of::nested_modules();
    }

The line `use a::series::of;` means that rather than using the full `a::series::of` path wherever we want to refer to the `of` module, we can use `of`.

The `use` keyword brings only what we’ve specified into scope: it does not bring children of modules into scope. That’s why we still have to use `of::nested_modules` when we want to call the `nested_modules` function.

We could have chosen to bring the function into scope by instead specifying the function in the `use` as follows:

    pub mod a {
        pub mod series {
            pub mod of {
                pub fn nested_modules() {}
            }
        }
    }

    use a::series::of::nested_modules;

    fn main() {
        nested_modules();
    }

Doing so allows us to exclude all the modules and reference the function directly.

Because enums also form a sort of namespace like modules, we can bring an enum’s variants into scope with `use` as well. For any kind of `use` statement, if you’re bringing multiple items from one namespace into scope, you can list them using curly brackets and commas in the last position, like so:

    enum TrafficLight {
        Red,
        Yellow,
        Green,
    }

    use TrafficLight::{Red, Yellow};

    fn main() {
        let red = Red;
        let yellow = Yellow;
        let green = TrafficLight::Green;
    }

We’re still specifying the `TrafficLight` namespace for the `Green` variant because we didn’t include `Green` in the `use` statement.

#### Nested groups in `use` declarations

If you have a complex module tree with many different submodules and you need to import a few items from each one, it might be useful to group all the imports in the same declaration to keep your code clean and avoid repeating the base modules’ name.

The `use` declaration supports nesting to help you in those cases, both with simple imports and glob ones. For example this snippets imports `bar`, `Foo`, all the items in `baz` and `Bar`:

    # #![allow(unused_imports, dead_code)]
    #
    # mod foo {
    #     pub mod bar {
    #         pub type Foo = ();
    #     }
    #     pub mod baz {
    #         pub mod quux {
    #             pub type Bar = ();
    #         }
    #     }
    # }
    #
    use foo::{
        bar::{self, Foo},
        baz::{*, quux::Bar},
    };
    #
    # fn main() {}

### Bringing All Names into Scope with a Glob

To bring all the items in a namespace into scope at once, we can use the `*` syntax, which is called the glob operator. This example brings all the variants of an enum into scope without having to list each specifically:

    enum TrafficLight {
        Red,
        Yellow,
        Green,
    }

    use TrafficLight::*;

    fn main() {
        let red = Red;
        let yellow = Yellow;
        let green = Green;
    }

The `*` will bring into scope all the visible items in the `TrafficLight` namespace. You should use globs sparingly: they are convenient, but a glob might also pull in more items than you expected and cause naming conflicts.

### Using `super` to Access a Parent Module

As you saw at the beginning of this chapter, when you create a library crate, Cargo makes a `tests` module for you. Let’s go into more detail about that now. In your `communicator` project, open src/lib.rs:

Filename: src/lib.rs

    pub mod client;

    pub mod network;

    #[cfg(test)]
    mod tests {
        #[test]
        fn it_works() {
            assert_eq!(2 + 2, 4);
        }
    }

Chapter 11 explains more about testing, but parts of this example should make sense now: we have a module named `tests` that lives next to our other modules and contains one function named `it_works`. Even though there are special annotations, the `tests` module is just another module! So our module hierarchy looks like this:

    communicator
     ├── client
     ├── network
     |   └── client
     └── tests

Tests are for exercising the code within our library, so let’s try to call our `client::connect` function from this `it_works` function, even though we won’t be checking any functionality right now. This won’t work yet:

Filename: src/lib.rs

    # #![allow(unused_variables)]
    #fn main() {
    #[cfg(test)]
    mod tests {
        #[test]
        fn it_works() {
            client::connect();
        }
    }
    #}

Run the tests by invoking the `cargo test` command:

    $ cargo test
       Compiling communicator v0.1.0 (file:///projects/communicator)
    error[E0433]: failed to resolve. Use of undeclared type or module `client`
     --> src/lib.rs:9:9
      |
    9 |         client::connect();
      |         ^^^^^^ Use of undeclared type or module `client`

The compilation failed, but why? We don’t need to place `communicator::` in front of the function, as we did in src/main.rs, because we are definitely within the `communicator` library crate here. The reason is that paths are always relative to the current module, which here is `tests`. The only exception is in a `use` statement, where paths are relative to the crate root by default. Our `tests` module needs the `client` module in its scope!

So how do we get back up one module in the module hierarchy to call the `client::connect` function in the `tests` module? In the `tests` module, we can either use leading colons to let Rust know that we want to start from the root and list the whole path, like this:

    ::client::connect();

Or, we can use `super` to move up one module in the hierarchy from our current module, like this:

    super::client::connect();

These two options don’t look that different in this example, but if you’re deeper in a module hierarchy, starting from the root every time would make your code lengthy. In those cases, using `super` to get from the current module to sibling modules is a good shortcut. Plus, if you’ve specified the path from the root in many places in your code and then rearrange your modules by moving a subtree to another place, you’ll end up needing to update the path in several places, which would be tedious.

It would also be annoying to have to type `super::` in each test, but you’ve already seen the tool for that solution: `use`! The `super::` functionality changes the path you give to `use` so it is relative to the parent module instead of to the root module.

For these reasons, in the `tests` module especially, `use super::something` is usually the best solution. So now our test looks like this:

Filename: src/lib.rs

    # #![allow(unused_variables)]
    #fn main() {
    #[cfg(test)]
    mod tests {
        use super::client;

        #[test]
        fn it_works() {
            client::connect();
        }
    }
    #}

When we run `cargo test` again, the test will pass, and the first part of the test result output will be the following:

    $ cargo test
       Compiling communicator v0.1.0 (file:///projects/communicator)
         Running target/debug/communicator-92007ddb5330fa5a

    running 1 test
    test tests::it_works ... ok

    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

## Summary

Now you know some new techniques for organizing your code! Use these techniques to group related functionality together, keep files from becoming too long, and present a tidy public API to your library users.

Next, we’ll look at some collection data structures in the standard library that you can use in your nice, neat code.