Modules
As you write larger Rust programs, you will start to accumulate large amounts of code. Depending on the complexity of your program, you may have hundreds or thousands of lines of code. Rather than having all this code in a single, large file, you can split it apart into modules.
You can use modules in Rust to separate code into different source files. This helps keep correlated code together, that shares a common theme or purpose.
Modules can contain Rust structs, traits, trait implementations, variables, and functions.
Use Cases for Rust Modules
As a developer, it's entirely your decision about how to split your code up into modules. However, there are some general use cases that you might want to consider using modules for:
- Code related to working with different storage engines: MySQL, Postgres, Redis, Amazon S3, etc.
- Define various aspects of a REST API: managing customers, products, payment methods, media files
- Separate modules for each type of widget you are manufacturing, eg. steering wheel, shift knob, turn signal lever
Define Inline Rust Module
One of the easiest ways to define a module is to simply add an inline module block to your existing program.
If you're building a simple Rust program with main.rs
, you might add a Customer
module to it.
Here's a simple, contrived example of an inline module that provides a couple of functions.
#![allow(unused)] fn main() { mod customer { pub fn create_customer() { println!("Creating new customer ..."); } pub fn deactivate_customer() { println!("Deactivating customer account ..."); } } }
âšī¸ NOTE: If you're wondering what the pub
keyword is, check out the "Item Visibility" section below.
Now that you've defined a couple of functions inside of a Rust module, you can call those functions from other parts
of your program.
In your main.rs
file, if you'd like to reference either of these functions, you can simply prefix them with the
module's name, similar to the following example.
fn main() { customer::create_customer(); }
If you'd like to try this out for yourself, why not use this example on the Rust Playground?
Nested Rust Modules
Rust supports multiple levels of the module hierarchy. You can create a module inside of another module. This helps you to establish groupings, as necessary, for your program.
#![allow(unused)] fn main() { mod database_adapters { pub mod mysql { pub static DB_NAME: &'static str = "MySQL"; } pub mod postgres { pub static DB_NAME: &'static str = "Postgres"; } pub mod mssql { pub static DB_NAME: &'static str = "Microsoft SQL Server"; } } }
If the child modules, and their members, are not marked with pub
visibility, then you will receive a compilation error when you try to access them
outside of the child modules themselves.
For example, if I remove pub
from the mssql
module, and try to compile a program that references the DB_NAME
variable in that module,
then this error would appear.
â error[E0603]: module
mssql
is private
If you'd like to try this out for yourself, why not use this example on the Rust Playground?
Define Module as Separate File
In a Rust project where you have main.rs
, let's say you want to add some functionality pertaining to people.
You decide to define a basic Person
struct, for starters.
#![allow(unused)] fn main() { pub struct Person<'p> { first_name: &'p str, last_name: &'p str, birth_date: &'p str, } }
Instead of placing this in main.rs
, place this struct definition into a new file, in the same directory as main.rs
, named person.rs
.
Then, go back to main.rs
and add the following line somewhere near the top of the file.
#![allow(unused)] fn main() { mod person; }
This statement will tell the Rust compiler to look for person.rs
and include it in the scope of the main.rs
file.
You should now be able to instantiate the Person
struct from your main()
function.
Specify the path to the struct, using module::struct
syntax, and then add the curly braces to pass in the initial field values.
fn main() { let p1 = person::Person { first_name: "Trevor", last_name: "Sullivan", birth_date: "2000-02-03" }; }
Item Visibility
By default, when you define any struct, function, variable, or trait (collectively, "items") in a Rust module, the item will
have a private visibility.
This means that the item cannot be used outside of that module.
If an item needs to be used outside of the module, then it must use the pub
visibility modifier.
Simply prefix the item's name with the pub
modifier to make it public, meaning it will be visible outside the containing module.
Here's how you'd make a Rust function visible outside its module:
#![allow(unused)] fn main() { person.rs pub struct Person { ... } }
Here's how you'd make a trait public from a module.
#![allow(unused)] fn main() { pub trait WalkOrRun { fn walk(distance: u8); fn run(speed: u8, time: u8); } }