What Are Packages,Crates And Modules in Rust?

What Are Packages,Crates And Modules in Rust?

What Are Packages,Crates And Modules in Rust?

INTRODUCTION

What names does the compiler realize at this location within the code?
What functions am I allowed to call? What does this variable refer to?
The Module System encompasses

Packages are a Cargo feature that permit us build, test, and share crates.
Crates are a tree of modules that produce a library or executable.
Modules and therefore the use keyword allow us to control the scope and privacy of paths.
A path may be a way of naming an item like a struct, function, or modules

PACKAGES AND CRATES for creating LIBRARIES AND EXECUTABLES :

A crate may be a binary or library.
The crate root may be a source file that’s wont to skills to create a crate.
A package features a Cargo.toml that describes the way to build one or more crates. at the most one crate during a package are often a library.
Example of a Package:

$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

THE MODULE SYSTEM to regulate SCOPE AND PRIVACY :

Features:
1. Modules, how to arrange code and control the privacy of paths
2. Paths, how to call items
3. A keyword use to bring a path into scope
4. pub, a keyword to form items public
5. Renaming items when bringing them into scope with the as keyword
6. Using external packages
7. Nested paths to wash up large use lists
8. Using the glob operator to bring everything during a module into scope
9. The way to split modules into individual files

MODULES :

Modules allow us to organize code into groups.
Example:
mod sound {
fn guitar() {
// Function body code goes here
}
}
fn main() {
}
MODULES (NESTED) :
mod sound {
mod instrument {
mod woodwind {
fn clarinet() {
// Function body code goes here
}
}
}
mod voice {
}
}
fn main() {
}
Hierarchy
crate
└── sound
├── instrument
│ └── woodwind
└── voice

MODULE TREE VS FILESYSTEM :

This tree might remind you of the directory tree of the filesystem we’ve on our computer. A bit like directories during a filesystem, you place code inside whichever module will create the organization you’d like. Another similarity is that to ask an item during a filesystem or a module tree, we use its path

PATHS :

If we would like to call a function, we’d like to understand its path.A path can take two forms: An absolute path starts from a crate root by employing a crate name or a literal “crate”. A relative path starts from the present module and uses “self”, “super”, or an identifier within the current module. The absolute and relative both paths are followed by one or more identifiers separated by double colons ( :: ) .

PATHS (EXAMPLE) :
mod sound {
mod instrument {
fn clarinet() {
// Function body code goes here
}
}
}
fn main() {
// Absolute path
crate::sound::instrument::clarinet();
// Relative path
sound::instrument::clarinet();
}

MODULES AS PRIVACY BOUNDARY :

Modules are used for organization
Modules also are used for privacy boundary in Rust.
Privacy rules:

○ All items (functions, methods, structs, enums, modules, and constants) are private by default.
we will use the pub keyword to form an item public.
○ We aren’t allowed to use private code defined in modules that are children of the present module.
○ We are allowed to use any code defined in ancestor modules or the present module.

PATHS (EXAMPLE WITH PUB) :

mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
fn main() {
// Absolute path
crate::sound::instrument::clarinet();
// Relative path
sound::instrument::clarinet();
}

STARTING RELATIVE PATHS WITH

fn
main() {} :
SUPER
mod instrument {
fn clarinet() {
super::breathe_in();
}
}
fn breathe_in() {
// Function body code goes here
}

USING PUB WITH STRUCTS :

mod plant {
pub struct Vegetable {
pub name: String,
id: i32,
}
impl Vegetable {
pub fn new(name: &str) -> Vegetable
{
Vegetable {
name: String::from(name),
id: 1,
}
}
}
}
fn main() {
let mut v =
plant::Vegetable::new(“squash”);
v.name = String::from(“butternut squash”);
println!(“{} are delicious”, v.name);
// println!(“The ID is {}”, v.id);
}

USING PUB WITH ENUMS :

mod menu {
pub enum Appetizer {
Soup,
Salad,
}
}
fn main() {
let order1 = menu::Appetizer::Soup;
let order2 = menu::Appetizer::Salad;
}

THE “USE” KEYWORD TO BRING ABSOLUTE PATHS INTO A SCOPE :

mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
use crate::sound::instrument;
fn main() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}

THE “USE” KEYWORD TO BRING RELATIVE PATHS INTO A SCOPE :

mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
use self::sound::instrument;
fn main() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}

ABSOLUTE VS RELATIVE PATHS WITH “USE” :

mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}}}
mod performance_group {
use crate::sound::instrument;
pub fn clarinet_trio() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
}}
fn main() {
performance_group::clarinet_trio();
}

Idiomatic use Paths for Functions

mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}
}
use crate::sound::instrument::clarinet;
fn main() {
clarinet();
clarinet();
clarinet();
}

Idiomatic use Paths for Structs/Enums & Other Items

use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
map.insert(1, 2);
}

Exception to the present idiom is that if the utilization statements would bring two items with an equivalent name into scope, which isn’t allowed.

use std::fmt; use std::io;
fn function1() -> fmt::Result {}
fn function2() -> io::Result {}
we might have two Result types within the same scope and Rust wouldn’t know which one we meant once we used Result.

Brought Into Scope with the as Keyword to Renaming Types

We will bring two sorts of an equivalent name into an equivalent scope.
We will specify a replacement local name for the sort by adding “as” and a replacement name after the “use”
Example:

use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result { }
fn function2() -> IoResult { }
Re-exporting Names with pub use

Once we bring a reputation into scope with the utilization keyword, the name being available within the new scope is private. If we would like to enable code calling our code to be ready to ask the sort as if it had been defined therein scope even as our code does, we will combine pub and use.This system is named re-exporting because we’re bringing an item into scope but also making that item available for others to bring into their scope.

Re-exporting Names with pub use (Example)

mod sound {
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
} } }
mod performance_group {
pub use crate::sound::instrument;
pub fn clarinet_trio() {
instrument::clarinet();
instrument::clarinet();
instrument::clarinet();
} }
fn main() { performance_group::clarinet_trio();
performance_group::instrument::clarinet(); }

Using External Packages

There are many packages that members of the community have published on https://crates.io.
Pulling any of them into our package involves following steps:

○ listing them in our package’s Cargo.toml
○ bringing items defined in them into a scope in our package with use.

Example: A package “rand” are often pulled with following code in

Cargo.toml file:
[dependencies]
rand = “0.5.5”
Nested Paths for Cleaning Up Large use Lists

Once we use many items defined by an equivalent package or within the same module, listing each item on its own line can take up tons of vertical space in our files.
for instance , these two use statements bring items from std into scope:

use std::cmp::Ordering;
use std::io;

we will use nested paths to bring an equivalent items into scope in one line rather than two as:

use std::{cmp::Ordering, io};

With the Glob Operator Bringing All Public Definitions into Scope

To bring all public items defined during a path into scope, you’ll specify that path followed by *, the glob operator
use std::collections::*;
Usually the glob operator is used when testing to bring everything under test into the tests module.The glob operator is additionally sometimes used as a part of the prelude pattern

Separating Modules into Different Files

Thus far we’ve defined multiple modules in one file.
When modules get large, you’ll want to maneuver their definitions to a separate file to form the code easier to navigate.

mod sound;
fn main() {
// Absolute path
crate::sound::instrument::clarinet();
// Relative path
sound::instrument::clarinet();
}

src/sound.rs file:
pub mod instrument {
pub fn clarinet() {
// Function body code goes here
}
}

The module tree remains an equivalent and therefore the function calls in main still work with none modification, albeit the definitions sleep in different files. This allows you to move modules to new files as they grow in size.

Leave a Comment