As Rust projects grow in complexity, it's important to organize code clearly, manage visibility smartly, and use idiomatic import patterns. Todayβs learning focused on:
- Absolute & Relative paths
- pub, super, use, as, *, and more
- Privacy rules in structs, enums, functions, modules
- Re-exporting & external crates
Letβs dive into each one π
π Absolute vs Relative Paths
Rust lets you access modules and items using:
β
Absolute paths β start from the crate root
crate::module::submodule::function();
β
Relative paths β start from the current module
self::submodule::function();
super::parent_module::function();
You can use them in both mod declarations and use imports.
π The pub Keyword β Managing Visibility
By default, everything is private in Rust β including modules, functions, structs, enums, and fields.
You must explicitly opt-in to make something public using the pub keyword.
πΉ Public vs Private: Modules & Functions
mod outer {
pub mod inner {
pub fn greet() {
println!("Hello from inner!");
}
fn secret() {
println!("This is private");
}
}
fn outer_fn() {} // private to crate::outer
}
fn main() {
outer::inner::greet(); // β
// outer::inner::secret(); β won't compile
}
mod is private unless marked pub
Functions are private to their module unless pub is used
You can access child modules from parent, but only if theyβre pub
Child modules cannot access parentβs private items unless exposed
β With Structs
You control visibility at the field level:
pub struct Flower {
pub name: String, // public
color: String, // private
}
Outside modules can create Flower but can only access the name field directly.
β With Enums
Enums behave differently. If an enum is pub, all of its variants are also public:
pub enum Color {
Red,
Green,
}
You cannot make individual enum variants private.
πΌ The super Keyword
Use super to refer to the parent module β helpful in nested module hierarchies.
// In src/garden/flowers.rs
fn bloom() {
super::tools::water(); // Access tools module in parent garden
}
This keeps your code modular and still lets you reach into parent modules when needed.
π§ The use Keyword β Clean Imports
Use use to bring items into scope. It avoids long paths and increases clarity.
use crate::garden::vegetables::Carrot;
fn main() {
let _ = Carrot {};
}
β
Idiomatic Grouping
use std::{io, cmp::Ordering};
β
Use Aliases with as
use std::collections::HashMap as Map;
let mut map = Map::new();
π Re-exporting with pub use
You can expose internal module items for cleaner APIs:
// garden/mod.rs
pub use self::vegetables::Tomato;
// main.rs
use crate::garden::Tomato;
This is a powerful pattern when building libraries or modules where you want to hide internal structure.
π¦ Using External Crates
To use packages from crates.io:
Add to Cargo.toml:
rand = "0.8.5"
Bring it into scope:
use rand::Rng;
let num = rand::thread_rng().gen_range(1..101);
Now you can use functions and types from the crate.
β¨ Glob Imports with *
You can bring all public items from a module:
use std::collections::*;
β οΈ Use this sparingly to avoid confusion and potential conflicts. Itβs often used in tests, preludes, or macro-heavy codebases.
π§ Bonus: Idiomatic Use Patterns
Group related imports for readability:
use std::{fmt, io};
Prefer pub use inside lib.rs or mod.rs to design clean APIs.
Avoid deeply nested paths in your main.rs β import what you need with use.
π§Ύ Summary
Today was all about Rustβs module system, path resolution, and visibility:
- Absolute vs relative paths
- pub, super, and privacy rules
- Struct & enum visibility
- Function and module scope
- use, as, *, pub use
- External crates
- Idiomatic import practices
These patterns help keep Rust code organized, safe, and scalable β essential skills for real-world projects.
π See you on Day 11 with more advanced Rust!
Top comments (0)