Welcome to Day 11 of my Rust journey! Today I dove deeper into Rust project organization and began exploring Rustβs standard collection types. In this post, weβll walk through:
- How to separate modules into different files
- Best practices around module visibility and structure
- Introduction to vectors, strings, and hash maps in Rust
π§© Separating Modules Into Different Files
As your project grows, stuffing everything into main.rs or lib.rs can get messy. Rust allows you to split modules into separate files, making your codebase more maintainable.
π Example Setup
Assume this was your original lib.rs:
mod front_of_house;
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
Now instead of keeping the whole module inline, we move front_of_house to its own file:
Create src/front_of_house.rs
pub mod hosting {
pub fn add_to_waitlist() {}
}
This is more idiomatic and scalable. Want to go further?
π§± Extracting Submodules into Subdirectories
If hosting grows, you can move it too:
Modify src/front_of_house.rs:
pub mod hosting;
Create the directory and file: src/front_of_house/hosting.rs
pub fn add_to_waitlist() {}
Rust infers this from the file structure automatically.
π Alternate File Paths
Rust supports two conventions for file structure:
Module Declaration | File Structure |
---|---|
mod front_of_house; | front_of_house.rs (recommended) |
front_of_house/mod.rs (older, still supported) |
Using mod.rs may clutter your workspace with identically-named files, so prefer the .rs variant directly.
π Module Visibility Recap
In Rust, everything is private by default. Use pub to make modules, functions, or structs available outside their scope.
mod my_mod {
pub fn public_func() {}
fn private_func() {}
}
You can also re-export symbols from one module to another:
pub use crate::my_mod::public_func;
This lets you provide a cleaner public API.
π Keywords Overview:
- mod β declares a module
- pub β makes it public
- use β brings an item into scope
- as β renames an import
- super β references parent module
π¦ External Packages
When using external crates like rand, you just add them to Cargo.toml and import as:
use rand::Rng;
π Common Collections in Rust
Rust provides powerful collections stored on the heap, enabling dynamic memory usage. Here's a quick look at three essential ones:
- Vectors (Vec) A growable array-like type.
Creating a Vector:
let mut v = Vec::new();
v.push(1);
v.push(2);
Or using a macro:
let v = vec![1, 2, 3];
Accessing Elements:
let third = &v[2];
let maybe_third = v.get(2);
get returns an Option, so it's safer.
Iterating:
for i in &v {
println!("{}", i);
}
You can also mutate values:
for i in &mut v {
*i += 10;
}
- Strings (String)
Rustβs String is a heap-allocated UTF-8 text collection.
Creating Strings:
let s1 = String::from("hello");
let s2 = "world".to_string();
Concatenation:
let hello = String::from("Hello, ");
let world = String::from("world!");
let greeting = hello + &world; // hello is moved
Use format! for non-consuming joins:
let s = format!("{} {}", "Hello", "World");
- Hash Maps (HashMap)
Associates keys with values, similar to JS objects or Python dictionaries.
Creating a HashMap:
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
Access and Update:
if let Some(score) = scores.get("Blue") {
println!("Score: {}", score);
}
scores.entry(String::from("Blue")).or_insert(50);
The entry API avoids overwriting and inserts default if key is missing.
π Summary
Today we covered:
- How to organize your Rust project into separate files and folders
- Understanding of mod, pub, use, super, as, and module visibility
- The idiomatic way to structure larger projects
Introduction to three essential collections:
Vec for dynamic arrays
String for heap-based text
HashMap for key-value storage
As Rust projects grow, mastering modular structure and leveraging built-in collections becomes essential.
Top comments (0)