Introduction to Rust

Rust Essentials

Introduction to Rust

Functions and Modules in Rust

Functions and Modules in Rust

Functions

You were first introduced to the function, arguably the most important part of a program. We have seen the main function, so let’s learn how to create other functions.

Here are examples of different types of functions in Rust.

  1. Function with No Return Statement or Argument:

fn greet() {
    println!("Hello, world!");
}

In this example, the greet function doesn't take any arguments or return any value. It simply prints out, "Hello, world!".

Function with Argument and No Return Statement:

fn say_hello(name: &str) {
    println!("Hello, {}!", name);
}

Here, the say_hello function takes a single argument of type &str (a string slice) and prints a personalized greeting using that argument.

Function with Argument and Return Statement:

fn square(n: i32) -> i32 {
    n * n
}

In this example, the square function takes an i32 argument and returns the square of that argument as an i32.

Function with Multiple Arguments and Return Statements:

fn calculate_power(base: f64, exponent: i32) -> f64 {
    if exponent == 0 {
        1.0
    } else {
        let mut result = base;
        for _ in 1..exponent.abs() {
            result *= base;
        }
        if exponent < 0 {
            1.0 / result
        } else {
            result
        }
    }
}

In this example, the calculate_power function takes a base of type f64 and an exponent of type i32. It calculates the base's power raised to the exponent, considering both positive and negative exponents.

You can call each of these in the main function and run the program with cargo:

fn main() {
fn main() {
    greet();
    say_hello("John");
    println!("{}", square(5));
    println!("{}", calculate_power(10.0, 10));
}
/* Output is:
❯ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/hello`
Hello, world
Hello, John
25
10000000000
*/

Note: The /* … */ is how to make longer, multi-line comments in Rust code. Also, the placeholders ({}) must be used to print out a message to the console. In Rust, the practice of printing out messages is often called debugging. Sometimes, the Rust compiler will not allow you to use the println macro for some operations because they do not support debugging.

Modules

If you know software engineering principles like hexagonal architecture, you will be familiar with modules. Generally, breaking down functions into different modules in a growing code base is best.

We can do this in Rust by leveraging the mod.rs file, a specially recognized and reserved file for Rust projects. Inside the src/ directory, you can also have other subdirectories called modules. Using them in the project must be linked to the main.rs or lib.rs file.

In Rust, modules organize code into separate, named units, allowing you to group related functions, types, and other items. This helps improve code organization, maintainability, and readability by breaking your program into smaller, manageable pieces.

Here's how you can work with modules in Rust. Inside the src/ directory, create a new directory called database. In it, create a mod.rs file and a model.rs file. The mod.rs file gives visibility to other files in any subdirectory under the src/ directory. To practically understand this, add the following code to the specified files:

mod.rs:

pub mod model;

model.rs:

pub fn create_user(name: &str, age: i32) {
    println!("New user created: {} of age {}", name, age);
}

main.rs:

pub mod database; // make the database module available in this file.
pub use database::*; // give this file access to all public modules and their functions (*) inside of the database module.

fn main() {
    let name = "John";
    let age = 35;
    database::model::create_user(name, age);
}

Note that we are using a clean main.rs file. Run the code with cargo, and you should see:

❯ cargo run
   Compiling hello v0.1.0 (/.../workspace/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.56s
     Running `target/debug/hello`
New user created: John of age 35

What did we do? We created a subdirectory, added a model.rs file, and exported it with mod.rs. We then called the subdirectory inside the main function (as we would do in any Rust source file that needs the contents of model.rs), and then we used the create_user function in the main function.

Note: In Rust, the double semicolon notation is used to call methods of a module/package, not the dot notation like in Go. Since we already specified to use all modules public modules and their respective functions using this line pub use database::*;, we can shorten the calling technique to this: model::create_user(name, age);.

We can also do this:

pub mod database;
pub use database::model::*;

fn main() {
    let name = "John";
    let age = 35;
   create_user(name, age);
}

Or this:

pub mod database;
pub use database::model::create_user; 
// use only the create_user function from the model module in the database package.

fn main() {
    let name = "John";
    let age = 35;
   create_user(name, age);
}

Ensure you get the logic before proceeding to the next section.

Note: Rust is feature-rich. For example, we can create separate modules inside one single Rust file using the mod keyword. We can also write modules inside the mod.rs file instead of having a separate model.rs file.

But this way shown above is a more maintainable and readable way to do it, as is the initial goal of modular programming. If your application is small and lightweight, you can do either, but use the approach taught here if it is bound to scale/grow bigger.

Whenever you're ready

There are 4 ways we can help you become a great backend engineer:

The MB Platform

Join 1000+ backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.

The MB Academy

The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

Join Backend Weekly

If you like post like this, you will absolutely enjoy our exclusive weekly newsletter, Sharing exclusive backend engineering resources to help you become a great Backend Engineer.

Get Backend Jobs

Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board