Lesson 10 of 12
Modules, Crates & Cargo
Learn how to split code into , use crates from crates.io, and manage builds, tests and dependencies with Cargo.
cargo new myapp # binary project
cargo new mylib --lib # library project
cargo add serde --features derive
cargo add tokio --features full
cargo run # build + run (debug)
cargo build --release # optimized build in target/release
cargo test # run all tests
cargo check # type-check only, much faster than build
cargo clippy # the linter. Listen to it, it is usually right.
cargo fmt # canonical formatting
cargo doc --open # build and read your own API docs
# Cargo.toml
# [package]
# name = "myapp"
# version = "0.1.0"
# edition = "2021"
#
# [dependencies]
# serde = { version = "1", features = ["derive"] }
# anyhow = "1"
#
# [dev-dependencies]
# criterion = "0.5"// src/lib.rs — the crate root
pub mod store { // an inline module
#[derive(Debug)]
pub struct Item {
pub name: String, // pub on the field too, or it stays private
quantity: u32, // private to this module
}
impl Item {
pub fn new(name: &str, quantity: u32) -> Self {
Self { name: name.to_string(), quantity }
}
pub fn quantity(&self) -> u32 { self.quantity }
}
pub mod pricing { // nested module
pub fn with_tax(amount: f64) -> f64 { amount * 1.23 }
pub(crate) fn internal_rate() -> f64 { 0.23 } // visible inside this crate only
}
}
// Bringing things into scope
use store::{Item, pricing::with_tax};
pub fn demo() {
let item = Item::new("keyboard", 3);
println!("{} x{} -> {:.2}", item.name, item.quantity(), with_tax(79.0));
}
// File-based modules: "mod store;" in lib.rs looks for
// src/store.rs or src/store/mod.rs
// and nested modules live in src/store/pricing.rs/// Adds two numbers.
///
/// # Examples
///
/// ```
/// assert_eq!(myapp::add(2, 3), 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 { return Err("division by zero".into()); }
Ok(a / b)
}
// Unit tests live in the same file, in a module compiled only for tests
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adds_numbers() {
assert_eq!(add(2, 3), 5);
}
#[test]
fn divides() {
assert!(divide(1.0, 0.0).is_err());
assert_eq!(divide(10.0, 4.0).unwrap(), 2.5);
}
#[test]
#[should_panic(expected = "index out of bounds")]
fn panics_on_bad_index() {
let v: Vec<i32> = vec![];
let _ = v[0];
}
}
// Integration tests go in tests/*.rs and see only the PUBLIC API.
// Doc examples in /// comments are compiled and run by "cargo test" too.Finished reading?Mark it done to track your progress.
Tip: use the ← and → keys to move between lessons.