DEV Community

Subesh Yadav
Subesh Yadav

Posted on

πŸš€ Day 11 of #100DaysOfRust: Organizing Modules Across Files & Intro to Common Collections

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

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

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;
Enter fullscreen mode Exit fullscreen mode

Create the directory and file: src/front_of_house/hosting.rs

pub fn add_to_waitlist() {}
Enter fullscreen mode Exit fullscreen mode

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

You can also re-export symbols from one module to another:

pub use crate::my_mod::public_func;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

🌟 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:

  1. Vectors (Vec) A growable array-like type.

Creating a Vector:

let mut v = Vec::new();
v.push(1);
v.push(2);
Enter fullscreen mode Exit fullscreen mode

Or using a macro:

let v = vec![1, 2, 3];
Enter fullscreen mode Exit fullscreen mode

Accessing Elements:

let third = &v[2];
let maybe_third = v.get(2);
Enter fullscreen mode Exit fullscreen mode

get returns an Option, so it's safer.

Iterating:

for i in &v {
    println!("{}", i);
}
Enter fullscreen mode Exit fullscreen mode

You can also mutate values:

for i in &mut v {
    *i += 10;
}
Enter fullscreen mode Exit fullscreen mode
  1. 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();
Enter fullscreen mode Exit fullscreen mode

Concatenation:

let hello = String::from("Hello, ");
let world = String::from("world!");
let greeting = hello + &world; // hello is moved
Enter fullscreen mode Exit fullscreen mode

Use format! for non-consuming joins:

let s = format!("{} {}", "Hello", "World");
Enter fullscreen mode Exit fullscreen mode
  1. 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);
Enter fullscreen mode Exit fullscreen mode

Access and Update:

if let Some(score) = scores.get("Blue") {
    println!("Score: {}", score);
}

scores.entry(String::from("Blue")).or_insert(50);
Enter fullscreen mode Exit fullscreen mode

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)