RustBrock/Modules and Use.md
2025-01-17 12:37:26 -07:00

275 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Use
``use`` the keyword
This is used to bring paths into scope
``pub`` keyword is used to make items public
``as`` keyword for globs and external packages
# Modules
## Cheat Sheet
- **Start from the Root Crate**: compiler starts here to look for code to compile
- Normally src/main.rs for binary crates or src/lib.rs for library crates
- **Declaring Modules**: These are declared in the crate root file
- For example if you had a module called garden
- it would be declared by ``mod garden;``
- The complier would then look in these places
- Inline, within curly brackets that replace the semicolon following `mod garden`
- In the file _src/garden.rs_
- In the file _src/garden/mod.rs
- **Declaring submodules**: in any other file you can declare submodules in any other file than the root
- it would be declared by ``mod vegetables;``
- The complier would then look in these places for the submodule
- Inline, directly following `mod vegetables`, within curly brackets instead of the semicolon
- In the file _src/garden/vegetables.rs_
- In the file _src/garden/vegetables/mod.rs
- **Paths to code in Modules**: once a module is part of your crate, you can refer to the code in that module form anywhere else in that same crate as long as the privacy rules allow using that part of the code
- Example ``Asparagus`` is a struct/type in the graden vegetables module would be found at ``crate::graden::vegetables::Asparagus``
- **Private vs. public**: code is private by default to the parent module to make it public.
- To make a module public declare it with ``pub mod`` instead of ``mod``.
- To make items within the public module public as well add ``pub`` before their declaration
- **The ``use`` keyword**: This is used to shorten the full path to just the last ``::`` in the declaration
- example use
- ``crate::garden::vegetables::Asparagus``
- to now
- ``use crate::garden::vegetables::Asparagus;``
- now can call this module by just ``Asparagus``
Here is how this example's file directory would look
```
backyard
├── Cargo.lock
├── Cargo.toml
└── src
├── garden
│ └── vegetables.rs
├── garden.rs
└── main.rs
```
src/main.rs
```rust
use crate::garden::vegetables::Asparagus;
pub mod garden;
fn main() {
let plant = Asparagus {};
println!("I'm growing {plant:?}!");
}
```
src/garden.rs
```rust
pub mod vegetables;
```
src/garden/vegetables.rs
```rust
#[derive(Debug)]
pub struct Asparagus {}
```
## Grouping Related Code in Modules
used to group code together and make easier to reuse
modules allow for the control of privacy, implementations needs to be declared as public otherwise it will be private by default not available to other modules if private
public modules and implementations can allow for different code to depend on it
this should be used to organize code like a file directory
## Use with Modules
This is a quick way to bring into scope a module then refer to the public items associated with module
Use can be used with either the entire module or just one part of the module
```rust
use crate::example_mod::sub_mod;
use crate::example_mod::sub_mod::example_funct;
// --snip--
// consumption
sub_mod::example_funct();
example_funct();
```
The use statement must be in the module scope if defined in the same file
ex of proper use
```rust
mod another_mod {
use crate::example_mod::sub_mod::example_funct;
// --snip--
}
// dont do this but you can
use crate::example_mod::sub_mod::example_funct;
mod another_mod {
use super::example_funct;
super::example_funct();
// --snip--
}
```
ex not allowed
<img style="height:5svh" src="https://doc.rust-lang.org/book/img/ferris/does_not_compile.svg" />
```rust
use crate::example_mod::sub_mod::example_funct;
mod another_mod {
// --snip--
}
```
### Use the Idiomatic Path
``use crate::example_mod::sub_mod;`` this is the idiomatic path due to being able to call functions, structs, etc. inside the mod
``use crate::example_mod::sub_mod::mod_fn;``
this is not idiomatic due to specifying only one thing in the module
this is great for letting others know it is not defined in the same module/crate as where it is being called this is only for functions
for structs and enums it makes more sense to bring the whole object into scope then using the methods associated
this is just convention in rust
the exception to this convention is when bringing who items with the name name into scope because rust wont allow that and no one can read which call it is supposed to be
```rust
use std::fmt;
use std::io;
fn function1() -> fmt::Result {
// --snip--
}
fn function2() -> io::Result<()> {
// --snip--
}
```
Result makes no sense unless looking at input or slight differences
Then use the parent mod to do so if this is the case
### Providing New Names with the ``as`` Keyword
Here is the other solution to the similar names problem
```rust
use std::fmt::Result;
use std::io::Result as IoResult;
fn function1() -> Result {
// --snip--
}
fn function2() -> IoResult<()> {
// --snip--
}
```
as you can now see Result and IoResult may be called the same thing under the hood but now you can differentiate between the two
this is also an accepted convention in rust
### Re-exporting Names with ``pub use``
the name that is brough into scope with use is private, but you can make it public to the whole module then you can add pub before use
```rust
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
}
```
this would be like defining it as if it was defining it in the scope that is desired
this also would have required front_of_house to also be marked public
this is useful when the internal structure of your code is different from how programmers would call your code
for example a customer would not think about frontend and backend they would think of add_to_waitlist and hosting not who's job it is
Will be added onto in ch 14
### Nested Paths/Shortening Use
this is a technique to shorten the use vertical space that it can often take up
```rust
use std::cmp::Ordering;
use std::io;
// this is the same as
use std::{cmp::Ordering, io};
```
this specifies a common path between the two
this can reduce the number of times that use shows up by A LOT
## Glob Operator on Use
Use if you want to bring all sub children of a path into scope
```rust
use std::collections::*;
```
This brings all public items defined in ``std::collections`` into the current scope
This makes it harder to tell what names are used in scope and where a name in used in your program
This is often used when testing to bring everything under test into the tests module
This is also used as part of the prelude pattern
## Modules In External Files
This works for both binary and library crates
leave only the mod definition in the crate root
```rust
mod example_mod;
```
then place the code that you want inside another file called example_mod.rs
```rust
pub mod inner_example_mod {
pub fn example_fn () {
}
}
```
you only need to to load a file using a ``mod`` declaration once in your module tree
The compiler will know the file is part of the project because of the mod declaration
mod is no an "include" operation like in C/C++ or python
you can then separate inner_example_mod into its own file called inner_example.rs
```rust
pub fn example_fn () {}
```
### Alternate File Patrhs
So far only use idiomatic file paths but you can also use older style of file paths. The compiler will also look for a module named front_of_house declared in the crate root, the compiler will look for the modules code in:
- src/front_of_house.rs (what we covered)
- src/front_of_house/mod.rs (older style, still supported path)
-
For a module named ``inner_example_mod`` that is a submodule of ``front_of_house``, the compiler will look for the modules code in:
- src/front_of_house/inner_example_mod.rs (what we covered)
- src/front_of_house/hosting/mod.rs (older style, still supported path)
If you mix both styles for the same module then you will get a compiler error
Using a mix of both styles for different modules is allowed but you will end up with many mod.rs files which can be confusing
No matter which style is used it will not change how the use path is setup
My preferred style:
- In the file _src/example_mod.rs_
- In the file _src/example_mod/mod.rs
- Only use if it makes sense
- In the file _src/example_mod/inner_example_mod.rs_