Modules
## Learning Objectives
- Organize code with modules
- Control visibility with pub
- Use use statements
- Work with crates and packages
- Understand the module system
## Why Modules?
Modules organize code into logical units:
- Group related functionality
- Control visibility (public/private)
- Avoid name conflicts
- Enable code reuse
## Module System Overview
```text
crate
└── module
├── submodule
└── subsubmodule
```
## Defining Modules
### Inline Modules
```rust
mod network {
fn connect() {
println!("Connecting...");
}
pub fn send(data: &str) {
connect();
println!("Sending: {}", data);
}
}
fn main() {
network::send("hello");
}
```
### Module File System
```text
src/
├── main.rs
├── network.rs (or network/mod.rs)
└── network/
└── mod.rs
```
### network.rs
```rust
pub fn send(data: &str) {
connect();
println!("Sending: {}", data);
}
fn connect() {
println!("Connecting...");
}
```
### main.rs
```rust
mod network;
fn main() {
network::send("hello");
}
```
## Visibility
### Public (pub)
```rust
mod outer {
pub mod inner {
pub fn public_function() {
println!("Public!");
}
pub(crate) fn crate_public() {
println!("Crate public!");
}
fn private_function() {
println!("Private!");
}
}
}
fn main() {
outer::inner::public_function();
// outer::inner::private_function(); // Error!
}
```
### Private
```rust
mod outer {
fn private() {
println!("Private outer");
}
pub fn public() {
private(); // Can call private
}
mod inner {
fn private_inner() {}
pub fn public_inner() {
private_inner(); // Can call sibling private
}
}
pub mod public_inner {
pub fn from_public_inner() {}
}
}
```
### pub(super) and pub(in path)
```rust
mod outer {
pub mod middle {
pub mod inner {
pub fn function() {}
}
pub(in outer) fn outer_only() {}
}
pub fn use_inner() {
middle::inner::function();
middle::outer_only(); // OK: within outer
}
}
```
## use Statements
### Bringing Items into Scope
```rust
mod network {
pub fn send(data: &str) {
println!("Sending: {}", data);
}
}
use network::send; // Bring into scope
fn main() {
send("hello"); // Direct call
}
```
### Full Path
```rust
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert("a", 1);
}
```
### Nested Paths
```rust
use std::collections::{HashMap, HashSet};
use std::io::{self, Write}; // Includes io itself
// Or glob
use std::collections::*;
```
### Renaming with as
```rust
use std::io::Result as IoResult;
use std::fmt::Result as FmtResult;
fn my_function() -> IoResult<()> {
Ok(())
}
```
### re-exporting with pub use
```rust
mod inner {
pub mod deeply {
pub fn nested_function() {}
}
}
pub use inner::deeply;
fn main() {
deeply::nested_function(); // Re-exported to outer scope
}
```
## Struct Visibility
```rust
mod my_module {
pub struct Secret {
pub data: String, // Public field
internal: String, // Private field (within crate)
secret: String, // Private field (only in module)
}
impl Secret {
pub fn new(data: String) -> Self {
Secret {
data,
internal: data.clone(),
secret: data,
}
}
pub fn get_internal(&self) -> &str {
&self.internal
}
}
}
fn main() {
let s = my_module::Secret::new("secret".to_string());
println!("{}", s.data); // OK: public
// println!("{}", s.internal); // Error: private
println!("{}", s.get_internal()); // OK: accessor method
}
```
## Enum Visibility
```rust
mod network {
pub enum PacketType {
Data, // Public by default
Ack,
}
pub struct Packet {
pub packet_type: PacketType, // Public field
data: Vec, // Private field
}
impl Packet {
pub fn new(packet_type: PacketType) -> Self {
Packet {
packet_type,
data: Vec::new(),
}
}
}
}
fn main() {
let packet = network::Packet::new(network::PacketType::Data);
println!("{:?}", packet.packet_type);
}
```
## Crates
### Library Crate
```text
my_crate/
├── Cargo.toml
└── src/
└── lib.rs
```
### src/lib.rs
```rust
pub mod utilities {
pub fn helper() {}
}
```
### Using Library Crate
```rust
use my_crate::utilities;
fn main() {
utilities::helper();
}
```
### Binary Crate
```text
my_project/
├── Cargo.toml
└── src/
└── main.rs
```
## Packages
A package contains one or more crates:
- One library crate (lib.rs) OR
- One or more binary crates (bin/)
```text
my_package/
├── Cargo.toml
├── src/
│ └── main.rs
└── src/
└── lib.rs (optional)
```
## The Module Tree
```rust
// src/main.rs or src/lib.rs
mod network { // network.rs or network/mod.rs
pub mod client;
pub mod server;
}
mod database { // database.rs or database/mod.rs
pub mod connection;
}
fn main() {
network::client::connect();
database::connection::connect();
}
```
## Best Practices
### File Structure
```text
src/
├── main.rs (binary crate root)
├── lib.rs (library crate root)
├── network/
│ ├── mod.rs
│ └── client.rs
│ └── server.rs
└── database/
├── mod.rs
└── connection.rs
```
### Module Naming
```rust
mod my_module; // snake_case
mod myGreatModule; // Don't do this
```
### Use Conventions
```rust
// Bring parent module into scope
mod outer {
pub mod inner {
pub fn function() {}
}
}
mod outer2 {
pub use super::outer::inner; // Re-export from parent
pub mod nested {
pub fn call_function() {
super::function(); // Call parent's function
}
}
}
```
## Summary
- Modules organize code logically
- `mod` keyword declares modules
- Files can be modules: `mod name;` looks for `name.rs` or `name/mod.rs`
- `pub` makes items public
- Private items only visible within declaring module
- `use` brings items into scope
- `pub use` re-exports items
- `super` refers to parent module
- Packages contain crates (one lib + optional bins)
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →