Packaging, Crates, and Modules
Crates
A crate is the smallest piece of code. It can be either a library or a binary.
Binaries are programs that compile into an executable, and must have a main
function. The entrypoint to a binary is src/main.rs
within the package.
Libraries are meant to be imported and used by other projects. The entrypoint to a library is src/lib.rs
and the compiler will create a library with the same name as the package.
Packages
A package is one or more crates that do something. It contains a cargo.yaml
file that describes how to build the package. A package can have multiple binary crates, but only one library crate.
Modules
Modules provide a way to break code into different files and use their paths to import/export functionality.
Cheat Sheet from the Rust Book
- Start from the crate root: When compiling a crate, the compiler first looks in the crate root file (usually
src/lib.rs
for a library crate orsrc/main.rs
for a binary crate) for code to compile. - Declaring modules: In the crate root file, you can declare new modules; say, you declare a “garden” module with
mod garden;
. The compiler will look for the module’s code 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
- Inline, within curly brackets that replace the semicolon following
- Declaring submodules: In any file other than the crate root, you can declare submodules. For example, you might declare
mod vegetables;
insrc/garden.rs
. The compiler will look for the submodule’s code within the directory named for the parent module in these places:- 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
- Inline, directly following
- Paths to code in modules: Once a module is part of your crate, you can refer to code in that module from anywhere else in that same crate, as long as the privacy rules allow, using the path to the code. For example, an
Asparagus
type in the garden vegetables module would be found atcrate::garden::vegetables::Asparagus
. - Private vs public: Code within a module is private from its parent modules by default. To make a module public, declare it with
pub mod
instead ofmod
. To make items within a public module public as well, usepub
before their declarations. - The
use
keyword: Within a scope, theuse
keyword creates shortcuts to items to reduce repetition of long paths. In any scope that can refer tocrate::garden::vegetables::Asparagus
, you can create a shortcut withuse crate::garden::vegetables::Asparagus;
and from then on you only need to writeAsparagus
to make use of that type in the scope.
Making things public
By default, everything you declare in rust is private. To make them public and usable by other files, use the pub
keyword.
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
pub enum Appetizer {
Soup,
Salad,
}
For libraries, or any other module, you can re-export a module with pub use
. Then you can import it from that re-exporting module's scope if it is deeply nested.
Additional shorthands
use std::cmp::Ordering;
use std::io;
// Becomes...
use std::{cmp::Ordering, io};
use std::io;
use std::io::Write;
// Becomes...
use std::io::{self, Write};
// Brings everything from that module into scope
use std::collections::*;
// Use with caution, because it becomes difficult to determine what is in scope