DEV Community

Cover image for [Rust Guide] 7.1. Package, Crate, and Module Definitions
SomeB1oody
SomeB1oody

Posted on

[Rust Guide] 7.1. Package, Crate, and Module Definitions

If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.

7.1.1 Rust Code Organization

Code organization mainly includes:

  • Which details can be exposed publicly, and which details are private
  • Which names are valid within a scope
  • ...

These features are collectively called the module system, which includes the following concepts, from broadest to most specific:

  • Package: a Cargo feature that lets you build, test, and share crates. You can think of it as a project
  • Crate: a module tree that can produce either a library or an executable
  • Module: it lets you control code organization, scope, and private paths
  • Path: a way to name items such as structs, functions, or modules

7.1.2 Packages and Crates

There are two types of crates:

  • Binary: an executable program that can run independently. It must contain a main function as the entry point. It is usually used to implement a concrete application or command-line tool.
  • Library: a reusable code module that cannot be run directly. It does not have a main function; instead, it exposes public functions or modules for other code to call.

A crate root refers to the source file (that is, a .rs file), and it is also the entry file such as main.rs. The Rust compiler starts here when building the root module of the crate.

A package contains:

  • A Cargo.toml file that describes how to build these crates
  • Either one library crate or no library crate
  • Any number of binary crates
  • But at least one crate, whether library or binary

7.1.3 Cargo Conventions

If you open the Cargo.toml of a local Rust project, for example mine:

[package]  
name = "RustStudy"  
version = "0.1.0"  
edition = "2021"  

[dependencies]  
rand = "0.8.5"
Enter fullscreen mode Exit fullscreen mode

you will notice that there is no mention of an entry file. That is because Cargo treats src/main.rs as the crate root of a binary crate by default, and the crate name is the same as the package name. In other words, the binary crate name and the package name are both RustStudy (as written on the second line of the TOML file). This reflects the idea that convention is better than configuration.

If this project, or package, has a lib.rs file under the src directory, that means the package contains a library crate, and that lib.rs is the crate root of the library crate. The crate name is also the same as the package name, which is RustStudy.

Cargo passes the crate root file to rustc to build the library or binary.

As mentioned earlier, a package can contain many binary crates. In that case, you can place source files (that is, .rs files) under the src/bin directory, and each file there is a separate binary crate (a separate program).

7.1.4 The Role of Crates

The role of a crate is to combine related functionality into a single scope, making it easier to share within a project. It also helps prevent naming conflicts. For example, to access the functionality of the rand crate, which generates random numbers, you need to use its name, rand.

7.1.5 Defining Modules to Control Scope and Privacy

A module is the feature that groups code inside a crate, dividing it into several modules. It improves readability and makes functionality easier to reuse. It can control the privacy of items—whether they are public or private.

To create a module, use the mod keyword, then write the module name after it, followed by curly braces.

Modules can also be nested, and the nested ones are called submodules. A module can contain definitions of other items such as structs, enums, constants, traits, and functions.

Let’s look at an example. Write this in lib.rs under the src directory:

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() {}
    }
}
Enter fullscreen mode Exit fullscreen mode

In this example, hosting and serving are submodules of front_of_house, and front_of_house is the parent module. Several functions are defined under these two submodules.

main.rs and lib.rs are called crate roots. The contents of these two files implicitly form a module named crate, which sits at the root of the entire module tree (the top level in the diagram). The following is the module tree for the lib.rs example above:

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

Enter fullscreen mode Exit fullscreen mode

Top comments (0)