Advanced

Modules and Packages

Organize code into modules and crates.

What you will see

15

About 2 min of reading

Try It

You will organize code into modules, import paths with use, and access crate dependencies.

1

I define a module with a public function and call it with the :: path. Modules create namespaces that control visibility.

mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } } fn main() { println!("{}", math::add(2, 3)); }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
5
2

I bring a path into scope with use, then write the short name. Imports avoid full qualification paths.

use std::collections::HashMap; fn main() { let mut map: HashMap = HashMap::new(); map.insert("a".into(), 1); println!("{}", map.len()); }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
1
3

I define a private item inside a module. Accessing it from outside the module fails to compile.

mod math { fn secret() -> i32 { 42 } } fn main() { println!("{}", math::secret()); }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
COMPILE_ERROR
Private items are only visible inside the module they are defined in.
4

I expose an item with pub so another module can access it. The public item is reachable through the path.

mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } fn private_add(a: i32, b: i32) -> i32 { a - b } } fn main() { println!("{}", math::add(10, 5)); }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
15
5

I re-export a name from one module under another path with a use declaration. The new name is usable elsewhere.

mod math { pub fn add(a: i32, b: i32) -> i32 { a + b } } use math::add; fn main() { println!("{}", add(7, 8)); }

Before you run it, say out loud what it will print. Then open the answer.

What it prints
15

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Modules nest code; crates bundle dependencies; Cargo builds them.
1 Define modules with pub items
↓
2 Import them with use
↓
3 Add dependencies in Cargo.toml
↓
4 Cargo compiles the crate
Why this works
Module visibility

Items are private by default:

mod inner {
    fn secret() {}        // private
    pub pub fn public() {} // visible
}

Add pub to make a module, item, or field visible to other modules. Without it, it is hidden. This keeps the public API small.

Cargo

Cargo manages Rust projects:

cargo new myapp
cargo build
cargo run
cargo test

Cargo.toml declares the crate name, version, and dependencies. Cargo.lock pins exact versions for reproducible builds.

Examples

Defining modules

Organizing code

mod math {
    pub fn add(a: i32, b: i32) -> i32 {
        a + b
    }
}

fn main() {
    println!("{}", math::add(2, 3));
}

A module groups related code. pub makes items visible outside the module. Use :: to access them.

Why it works: modules create nested namespaces and control visibility.

Use statements

Bringing names into scope

use std::collections::HashMap;

fn main() {
    let map: HashMap<String, i32> = HashMap::new();
}

use imports a path into scope so you can write HashMap instead of the full path. use std::collections::HashMap; imports the type.

Why it works: imports avoid long qualification paths.

Crates and dependencies

External code

# Cargo.toml
[dependencies]
rand = "0.8"

use rand::Rng;
let n = Rng::gen_range(&mut rng, 1..=100);

A crate is a package. Cargo.toml lists dependencies. cargo build downloads them from crates.io.

Why it works: Cargo is Rust's build and package manager.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Error Handling
Previous Lesson
Error Handling
Next Lesson
Concurrency
Concurrency →