Crates, Packages & Modules in Rust

Crates, Packages & Modules in Rust

Introduction

The programs we're writing till now are all small programs. Mostly contained inside one file main.rs and that's okay. But when we're working on a bigger project, let's say a multi-player game, and we're writing all our code inside main.rs then it's a big big problem!

And how to resolve that problem is what we'll be discussing today.

Crates

Crates are the smallest unit of code in a Rust Program.

Crates can be divided into binary crate and library crate

Binary crates are compiled and converted into an executable. Executables are nothing but binary files, the machine can directly run.

Library crates do not get compiled and converted into an executable. They're like libraries (taking the analogy of other Programming languages) that store logic, can be import-exported.

One more thing to note is that, binary crates must have a main function, from where the Program execution begins. Library crates on the otherhand do not contain the main function, because library crates do not get executed.

Packages

A package is a bundle of crates. It contains a Cargo.toml file. TOML stands for "Tom's Obvious Minimal Language" that contains configuration settings of the Package, and specifies how to build the crates.

cargo new my_proj

We'll create a Package by running this command that contains a Cargo.toml file. We have done that many times already. This package will contain a binary crate. To create a library crate we have to run this command.

cargo new my_proj --lib

Very Simple!

One thing to note here is, a Package may contain many binary crates, but at most one library crate. Also, the Package must contain atleast one crate, that could be a binary crate or a library crate.

Modules

Modules are a way to organize Code in Rust by grouping together related functionalities in separate files, often in a tree-like structure.

To give an example in the root crate main.rs let's declare a module using the mod keyword.

mod example_mod;

Now the compiler will search for the example mod in the following 3 places:

  1. In the same file if we have code, example_mod { ... }

  2. In src/example_mod.rs

  3. In src/example_mod/mod.rs

In this way we're able to extend our main.rs file into multiple files allowing us to better organize our code, but everything will still be part of the same binary crate.

Now following the same format we can also declare sub-modules.

How To use Modules?

Let's say we have the following code in our example_mod.rs

pub fn hello() {
    println!("Hello from example mod.")
}

First of all, we're using the pub keyword to declare our function. It means the visibility of the following function is public, in other words, can be accessed from anywhere.

We can also choose not to use the pub keyword, in case we want to keep methods and outcomes private.

Now let's see how can we use the module in our main.rs

mod example_mod;

fn main() {
    println!("Hello, world!");
    example_mod::hello();
}

This is how we can use. Else, we can also use the use keyword.

mod example_mod;

use example_mod::hello;

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

Hence from now on I'm quite convinced that we'll have no issues in case our project gets bigger and bigger, because it'll start getting very big soon!

Conclusion

That's all for now. We'll discuss about these topics more. In Rust there is never a shortage of things to learn! So see you once again in another Rusty Blog, and Cheers!