Rust 101: Modules

Mukundh Bhushan
6 min readMay 27, 2020

--

In the previous article, we discussed about functions in rust. Now let’s dive into Modules.

TL;DR

  • What are modules?
  • Basic module
  • Nested modules
  • The “use” keyword
  • “as” keyword
  • Importing specific functions from a module
  • Super and self

First, let’s start off by creating a new project called “modules” using the following command.

cargo new Modules --bin

What are modules?

Modules in rust allow you to split and organize your code better. It provides a method to manage visibility throughout your code base. Modules can contain functions, nested modules, structures, traits, implementations, etc.

Basic modules

Modules can contain public and private entities. By default, the module and its contents are private.

Here is the syntax

//Defining a module
pub mod <mod name> {
//Code block}//importing a module
mod <file name>;
let <var name> = <file name>::<mod name>::<function name>;

Defining and calling a module in the same file

Let’s implement two functions under a module, one which adds two given numbers and the other which adds all sum of all numbers in a given vector.

Code in main.rs

If we were to change the module adder from public to private, this program will still run. But it would throw an error if one of the function was private as in this case.

Rust cannot import the function as it not under the same hierarchy as the module adder. That's why the module can be called but not the private function defined in it.

Defining and calling a module in different files

The “mod” keyword is used to import the contents form a file.

The function which can be imported must have the “pub” keyword which makes the function public, Private functions cannot be imported.

Unlike, many other programming languages which use the “.” operator, Rust uses the “::” as the call operator.

Here is my file structure for this scenario

mediumrust/Modules/
├── src
│ ├── main.rs
│ └── add.rs
├── target
│ ├── debug
│ ├── rls

├── Cargo.lock
├── Cargo.toml

Under the “src” folder I have 2 files main.rs and add.rs. The above functions are now part of the “add.rs” file.

Code in add.rs

Code in main.rs

Unlike previous article this time the module was imported and not the function themselves hence the extra “::” were used.

Because the module is in a different file it must be public to be imported and the same goes for the contents inside the modules.

We can use call functions within the modules the same way we call any other function as shown in the code below.

Nested modules

Modules within a module are called nested modules. Each of these modules and their corresponding contents are private by default.

Let's use the same addition functions but the vector’s function in a nested module

Code in add.rs

Code in main.rs

Now that the hierarchy has changed for the “vec_add” function we need to add the additional “::”.

Calling a nested modules function in the parent module

Let’s try to call hello_parent() function in child module

This will throw an error hence we use “super” which we will learn in later section of this article.

The “use” keyword

“use” is mostly used when importing 3rd party or inbuilt standard libraries which are part of rust. It is a good practice to use “use” to import user defined modules instead of using mod directly.

Here is a code snippet on making a cli tool in rust.

If we were to use “use” for our addition program, here is how it would have looked like.

Code in main.rs

We need to use the “create” keyword.

We can call the nested module directly from the “add::adder” like “add::adder::nested_adder” instead of importing the nested module separately.

The “as” keyword

If you are familiar with python the “as” in rust is similar to python’s

import <lib> as <alias>

“as” allows us to assign an alias to our import statements. Here is know it looks in Rust

use <lib>::<module> as <alias>

This is how our nested module addition program will look like using “as”…

Code in add.rs

Code in main.rs

“as” can be used only if you are using “use” and does not work with the plain old “mod”.

Importing specific functions from a module

Rust allows you to import only the necessary modules from a file instead of the entire file contents. This can be used for user defined, standard inbuilt or 3rd partly libraries.

Syntax

//for inbuilt and 3rd party modules
use <lib name>::{<module name1>,<module name2>}

Importing from user defined module

As we need more modules in our add.rs we will split the digit adder and the vector adder into two separate modules

Code in add.rs

Code in main.rs

Let import only the vector adder module

If you run this code rust will throw a warning stating that the add module is not used. Ignore it.

Super and self

In the above section we tried to use a parent module’s function in the child or. nested module which did not work. Here is where the “self” and “super” are used.

Self is used to refer to the current module in scope
Super is used to refer to the parent module in scope i.e. a level higher in the hierarchy.

Multiple supers can be attached to each other to move higher up the hierarchy.

Consider the below piece of code.
It consists of 3 modules parent, child and child2.

Child2 inherits from child and parent. Child inherits from parent only.

Output of the following code

...Parent...
hello I am parent!
hello I am child!
hello I am child2!
...Child...
hello I am child!
hello I am child!
hello I am parent!
hello I am child!
hello I am child2!
...Child2...
hello I am child2!
hello I am child2!
hello I am child!
hello I am parent!
hello I am child!

In the next article, we will discuss about Structures.

link to the next article

Link to the previous article

--

--