Focus mode

Rust Programming

Modules and visibility

Introduction to Modules and Visibility in Rust

In Rust, we have a handy feature known as Modules. Picture a busy library with thousands of books. Now, if these books were just scattered around, it'd be a chaotic mess. That's where the librarian steps in, organizing these books neatly into different sections or 'modules'. That's exactly what modules do in Rust. They help us manage and neatly arrange our code, making it readable and maintainable.

Modules in Rust serve as a sort of namespace. They group related definitions together, and that could be anything - functions, structs, traits, enums, or even other modules. It's like your family tree, but instead of relatives, you have chunks of code.

mod sports {
    pub fn football() {
        println!("Football is fun!");
    }

    fn basketball() {
        println!("Basketball is intense!");
    }
}


In the code snippet above, sports is a module that contains two functions: football and basketball. You can think of sports as a big box that contains smaller boxes. Each smaller box is a function. But wait, why does football have this pub keyword in front of it? Good question, dear reader!

This brings us to the concept of Visibility. Let's stick with our library analogy. Not every book in the library is available for everyone to read. Some are reserved, kept behind the counter. Similarly, in Rust, not all parts of your module need to be accessible to everyone.

The pub keyword is Rust's way of saying, "Hey, this function is for everyone! Come and use it." So, pub fn football() means that the football function can be accessed from outside the sports module. But fn basketball() is a shy function. It doesn't have the pub keyword, so it's hidden away from the outside world. It's only accessible within the sports module.

fn main() {
    sports::football();    // This works!
    sports::basketball();  // This doesn't. basketball() is private to the sports module.
}


In a nutshell, Visibility in Rust is about controlling who can see and use your code. It's like the curtains on your window - you decide when to draw them and who gets to peek into your room.

So, in Rust, Modules and Visibility are like best buddies. Modules help to organize your code into different sections, and Visibility rules determine who can access these sections. Just like in a library, where sections help organize books and access rules determine who can read them. Pretty neat, right?

Alright, that's enough for the introduction. In the next section, we'll dive deeper into defining and using modules. Buckle up! It's going to be an exciting ride!

Defining and Using Modules

Let's dive into the world of modules, shall we? Picture a large library with hundreds of books. 

Now imagine if they were all scattered haphazardly. It would be a nightmare to find the one book you need, wouldn't it? Well, this is where our good friend, the mod keyword, comes into play. Just like a library organizes books, mod helps us organize our Rust code. It's like a librarian for your code, and who doesn't love librarians?

How to Define a Module using the mod Keyword

Defining a module in Rust is as easy as pie. All you need is the mod keyword. Think of mod as a magic word. Every time you use it, you're creating a new, neat little box to hold your code. Here's how you do it:

mod my_module {
    // Your fantastic code goes here
}


With that, my_module is now a part of your code's library. This module can have functions, structs, enums - you name it! It's like a mini playground for your code.

Nesting Modules: Because One Playground is Never Enough!

Remember how we can nest dolls inside bigger dolls? Well, we can do the same with modules in Rust. A module inside a module - sounds fun, right? And it's just as easy! Here's how you can create a nested module:

mod my_module {
    mod my_nested_module {
        // Your even more fantastic code goes here
    }
}


And voila! You have a module within a module. It's like inception, but for code. Who said coding isn't fun?

Defining Functions, Structs, and Enums within a Module

But what is a playground without some games, right? Inside your modules, you can define functions, structs, and enums. Think of them as the slides, swings, and see-saws of your playground.

Here's how to define a function within a module:

mod my_module {
    pub fn say_hello() {
        println!("Hello from my_module!");
    }
}


Just like that, we've added a function say_hello to our module! You can do the same with structs and enums. Easy peasy, lemon squeezy!

So, there you have it! You're now a module master. With the mod keyword, you're ready to organize your code like a pro. Happy coding, and remember to have fun with it! After all, who said modules can't be fun?

Understanding Visibility and Privacy

Welcome, Rustaceans! Let's delve into the mysterious world of visibility and privacy in Rust. Don't worry, it's not as scary as it sounds, and no, we're not talking about incognito mode in your web browser or deleting your internet history.

The first thing you need to know is that in Rust, all items (functions, methods, structs, enums, modules, and constants) are private by default. Yeah, you heard right, they are shy and prefer to keep to themselves. But fear not, Rust has a magical keyword pub that can make them come out of their shell.

The pub Keyword

Imagine you're at a grand ball (yes, we programmers do get out sometimes). You see a group of functions, structs, and enums, all huddled in a corner, too shy to dance. How do we get them to join the party? We introduce them to our magic word, pub.

In the Rust world, pub is equivalent to saying "Hey, you're cool, you can join our party!". When we put pub in front of an item, it makes that item public, allowing it to be accessed from outside the module.

mod my_module {
    pub fn public_function() {
        println!("I'm visible to the world!");
    }

    fn private_function() {
        println!("I'm shy...");
    }
}

fn main() {
    my_module::public_function();  // Works fine
    my_module::private_function(); // Error! This function is private.
}


In the above code, public_function() is having a great time at the ball, visible to all, while private_function() is still in the corner, inaccessible from outside the my_module module.

Public and Private Items

Let's clear the air on public and private items. Public items are like social butterflies. They are accessible from outside the module. On the other hand, private items are more like introverts; they are only accessible from their current module and its child modules.

In the following example, we've got a struct Person with a public field name and a private field age. The name field is an open book, but age is a closely guarded secret.

mod my_module {
    pub struct Person {
        pub name: String,
        age: u8,
    }
}


In this scenario, you can create a Person and set their name from outside the my_module, but you can't set their age. It's as if they responded, "You can call me by my name, but my age is none of your business!"

Well, that's it for our lesson on Rust's visibility and privacy. Remember, just like people, every function, struct, enum, and module has their own level of comfort with public visibility, and Rust respects that!

Importing and Using Modules with use

Hello again! Just like the morning coffee that brings you into scope for the day, in Rust, we have the use keyword that brings module paths into scope for us. Let's dive into it!

The Magic Wand: use Keyword

Now, you might be wondering, "I've defined my modules, but how do I actually use them? Do I have to write the full path every time?" Well, Rust has got you covered with the use keyword. It's kind of like the "Accio" spell in Harry Potter; it brings what you need right to your fingertips.

mod delicious_fruits {
    pub mod apple {
        pub fn munch() {
            println!("Munching an apple...");
        }
    }
}

use delicious_fruits::apple;

fn main() {
    apple::munch();  // Look, Ma! No hands!
}


In this code, instead of writing delicious_fruits::apple::munch(), we can simply write apple::munch(). Neat, right?

Absolute vs Relative Paths

Remember, with great power comes great responsibility. The use keyword can use both absolute and relative paths. Absolute paths start from the crate root by using a crate name or a literal crate.

// Absolute path
use crate::delicious_fruits::apple;

Relative paths start from the current module and use self, super, or an identifier in the current module.

// Relative path
use self::delicious_fruits::apple;


It's like choosing to use GPS coordinates or saying "it's the third door on the left". Both will get you to the destination, but the choice is yours.

Visibility and the use Keyword

The use keyword also respects Rust's privacy rules. If you try to use a path that is private, Rust will throw a fit (a.k.a. a compiler error). This is Rust's way of preventing gossip—er, I mean, information—from unnecessarily spreading around.

mod delicious_fruits {
    mod apple {   // Notice this isn't public
        pub fn munch() {
            println!("Munching an apple...");
        }
    }
}

// This will cause a compiler error!
use delicious_fruits::apple;  // apple module is private!

fn main() {
    apple::munch();  
}


In the above example, Rust will stop you because the apple module is private. It's like trying to read a secret diary. Not cool!

And that's it! With the use keyword, you're now a certified Rust magician. Just remember to respect the privacy rules, and you'll be summoning code paths like a pro!

Comments

You need to enroll in the course to be able to comment!