Modules to Control Scope and Privacy

0
Modules in Rust allow us to structure our code logically, group related functionality together, and manage visibility. They provide a way to organize code within a crate, making it more readable and maintainable. 

Key concepts

1. Start from the Crate Root:
  • When compiling a crate, the compiler begins by looking in the crate root file (usually `src/lib.rs` for a library crate or `src/main.rs` for a binary crate).
  • The crate root file contains the initial code to compile and serves as the entry point for the module system.
2. Declaring Modules:
  • In the crate root file, we can declare new modules using the `mod` keyword.
  • For example, declaring a "garden" module: `mod garden;`.
  • The compiler searches for the module's code in several places:
    • Inline within curly brackets that replace the semicolon following `mod garden`.
    • In the file `src/garden.rs`.
    • In the file `src/garden/mod.rs`.
3. Declaring Submodules:
  • In any file other than the crate root, we can declare submodules.
  • For instance, declaring `mod vegetables;` in `src/garden.rs`.
  • The compiler looks for the submodule's code within the directory named for the parent module:
    • Inline, directly following `mod vegetables`, within curly brackets.
    • In the file `src/garden/vegetables.rs`.
    • In the file `src/garden/vegetables/mod.rs`.
4. Paths to Code in Modules:
  • Once a module is part of your crate, you can refer to its code from anywhere else in the same crate.
  • Use the path to the code, such as `crate::garden::vegetables::Asparagus`.
  • Privacy rules apply: you can access code within the same crate as long as visibility allows.
5. Private vs. Public:
  • By default, code within a module is private to its parent modules.
  • To make a module public, declare it with `pub mod` instead of `mod`.
  • Use `pub` before item declarations to make them public within a public module.
6. The `use` Keyword:
  • Within a scope, `use` creates shortcuts to items, reducing repetition of long paths.
  • For example, `use crate::garden::vegetables::Asparagus;`.
  • Afterward, you only need to write `Asparagus` to use that type in the scope.

Example: Creating a Restaurant Library

Let's apply these concepts to a practical example. Imagine we're building a restaurant library. We'll define function signatures for restaurant operations without implementing their bodies. Our focus is on organizing the code.

Front of House Section:

Rust
// Filename: src/lib.rs

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

    mod serving {
        fn take_order() {}
        fn serve_order() {}
        fn take_payment() {}
    }
}
  • We create a module named `front_of_house`.
  • Inside it, we have nested modules: `hosting` and `serving`.
  • Modules allow us to group related functionality (e.g., seating customers, taking orders) and control visibility.

Module Tree:

crate
└── front_of_house
    ├── hosting
    │   ├── add_to_waitlist
    │   └── seat_at_table
    └── serving
        ├── take_order
        ├── serve_order
        └── take_payment

  • The entire module tree is rooted under the implicit module named `crate`.
  • Just like directories in a filesystem, modules help organize our code.

Post a Comment

0Comments
Post a Comment (0)