How to Read This Book
Click on the "three stacked bars" (on the top left corner) to reveal the left sidebar and the table of contents.
The book is organized in a few major sections. Click on a heading to expand it and navigate to chapters within the book.
-
The book first summarizes the basics of the language and often-used elements of the standard library. The code organization section explains how Rust code should be structured.
-
The bulk of the book focuses on the Rust ecosystem and is divided in sections named after the
crates.io
↗ categories↗, whenever possible. -
Each section contains a list of recipes. The recipes are simple statements of a task to accomplish, like "generate random numbers in a range"; and each recipe is tagged with badges indicating which crates they use, like
, and which categories on
crates.io
↗ those crates belong to, like.
-
The crate selection chapter provides pointers on how to locate crates suitable for your project and provides alphabetical and categorical indices of crates used in the book.
-
The links section provides pointers to notable Rust websites, learning resources, cheat sheets, books, and code examples.
The contributing section details how to contribute to the book itself.
If you are simply looking for the solution to a given task, the easiest ways to find a specific recipe are to:
- Use the search button (in the top toolbar),
- Scan the left-side bar for categories you are interested in,
- Scan the index of examples, and from there, click on the name of the recipe to view it,
- Look up into the word index lists concepts, crates (in lower case), and Rust items (using their full path e.g.
parking_lot::ReentrantMutex
↗), - Consult the alphabetical and categorical crates indices.
Important Sections
- The book covers cross-cutting concerns that affect most aspects of development e.g. error handling, error customization, configuration, debugging...
- Concurrency, including asynchronous programming, is covered in details.
- So are development tools and programming domains such as CLI and Web development.
How to Use the Code Examples
Code examples, a.k.a. Recipes, are designed to give you instant access to working code, along with a full explanation of what it is doing, and to guide you to further information. All recipes are self-contained programs, so that they may be copied directly into your own projects for experimentation. To do so, follow the instructions below.
Consider the following example for "generate random numbers within a range":
use rand::Rng; /// This is a simple example that demonstrates how to use the `rand` crate to /// generate a random `f64`. fn main() { // Get a thread-local random number generator. let mut rng = rand::rng(); // Generate a random `f64`. println!("Random f64: {}", rng.random::<f64>()); }
To work with it locally we can run the following commands to create a new cargo
↗ project, and change to that directory:
cargo new my-example --bin
cd my-example
Now, we also need to add the necessary crates to Cargo.toml↗, as indicated by the crate badges, in this case just "rand". To do so, we'll use the cargo add
↗ command.
cargo add rand
Next you can replace src/main.rs
with the full contents of the example and run it:
cargo run
The crate badges that accompany the examples link to the crates' full documentation on docs.rs
↗, and is often the next documentation you should read after deciding which crate suites your purpose.
A Note about Error Handling
Error handling in Rust is robust when done correctly, but can require a fair bit of boilerplate. Because of this, one often sees Rust examples filled with unwrap
↗ calls, instead of proper error handling.
Since this book's recipes are intended to be reused as-is and encourage best practices, they set up error handling correctly when there are Result
↗ types involved. The structure generally looks like:
//! This example demonstrates converting a byte slice representing an IPv6 //! address to an `IpAddr` type. use std::net::IpAddr; use std::str; use anyhow::Result; fn main() -> Result<()> { // A byte slice representing an IPv6 address. let bytes = b"2001:db8::1"; // Convert the byte slice to a string slice. let s = str::from_utf8(bytes)?; // Parse the String to an IP address. let addr: IpAddr = s.parse()?; println!("{addr:?}"); Ok(()) }
//! This example demonstrates how to parse a URL and extract a portion of it. use anyhow::Result; use url::Position; use url::Url; fn main() -> Result<()> { let parsed = Url::parse("https://httpbin.org/cookies/set?k2=v2&k1=v1")?; // Extract the portion of the URL up to the end of the path. let cleaned: &str = &parsed[..Position::AfterPath]; println!("cleaned: {cleaned}"); Ok(()) }
In most examples, we have chosen to use anyhow
↗'s Result
↗ as the return type of any fallible function, instead of writing std::result::Result<_, Box<dyn std::error::Error>>
or using custom Result
↗ / Error
↗ types.
Within the code, we use the ?
↗ operator to easily propagate any error that implements the std::error::Error
↗ trait.
For more background on error handling in Rust, read this page↗ of the 'Rust book'.
Additional Examples
The xmpl
↗ folder in the book's GitHub repo contains additional examples that can't be embedded into the book, due to their length.
A Note about Crate Representation
This book provides expansive coverage of "key" or "foundational" crates - the crates that make up the most common programming tasks, and that the rest of the ecosystem builds off of.
Key crates were identified by cross-referencing blessed.rs
↗, most downloaded crates (overall and per category) in crates.io
↗, most popular Rust libraries↗ and high-quality crates per lib.rs
↗ statistics↗.
This said, the crate selection process is necessarily opinionated. Feel free to offer suggestions (or submit a PR to the book's GitHub repo), if the author missed an important, widely used crate.