How to Read This Book
Click on the "three stacked bars" on the top left corner, in order to reveal the table of contents in the left sidebar.
The book is organized in a few major sections. Click on a heading (with an arrow) to expand it and navigate to chapters within the book.
- The book first summarizes core concepts of the language and often-used elements of the standard library (if they are not covered elsewhere). The code organization section explains how Rust code should be structured, depending on your project's needs.
- The bulk of the book focuses on the Rust ecosystem, meaning Rust tools and public libraries that you reuse in your project. It is divided in subsections named, whenever possible, after the categories↗ of
crates.io
↗, the central registry of public Rust crates. That means you can easily list and search for related crates usingcrates.io
orlib.rs
↗. - Each chapter within each subsection 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 in the "Resources" section provides additional pointers on how to locate crates suitable for your project.
- The links section provides pointers to notable Rust websites, learning resources, cheat sheets, books, code examples, etc.
- The indices includes a word index, an index of examples in the book, and provides alphabetical and categorical lists of crates used in the book.
- The contributing section details how to contribute to the book itself.
Look for a Solution for a Specific Task
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, which 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, then search for the crate name.
Use the Code Examples
Code examples, a.k.a. recipes, are designed to give you instant access to working code, along with an explanation of what it is doing, and to guide you to further information. Most recipes can be copied to the clipboard; edited in place; and run on the Rust playground by clicking the "right arrow" button. The results, if any, are displayed below the example.
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 generating a random number:
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, you can run the following commands to create a new cargo
↗ project, and change to that directory:
cargo new myexample
cd myexample
You also need to add the necessary crates to Cargo.toml↗, as indicated by the crate badges, in this case just the "rand" crate. To do so, 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 several key webpages, including the crates' full documentation on docs.rs
↗, which is often the next documentation you should read after deciding which crate suits your purpose. The category badges next to them link to the corresponding page on crates.io
, which lists related crates.
Read 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 Error Handling
Error handling in Rust is robust but can require a 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.
In most examples, we have chosen to use anyhow::Result
↗ (from the anyhow
↗ crate) as the return type of any fallible function (instead of writing std::result::Result<_, Box<dyn std::error::Error>>
or using custom Result
↗ or Error
↗ types). Within the code, we use the ?
↗ operator to easily propagate any error that implements the std::error::Error
↗ trait. The structure generally looks like the following:
//! This example demonstrates converting a byte slice representing an IPv6 //! address to an `IpAddr` type. use std::net::IpAddr; use std::str; // This function includes calls that can fail. // - Errors are caught and propagated back to the caller with the `?` operator. // - Note how the function returns a `Result` type. // - We have chosen to use the flexible `Result` type alias from the very // commonly used `anyhow` library. // - This function does not panic. fn example() -> anyhow::Result<()> { // A byte slice representing an IPv6 address: let bytes = b"2001:db8::1"; // Convert the byte slice to a string slice. // This operation can fail if the bytes are not UTF-8. Therefore it returns // a `Result`. The `?` operator causes an early return in case of error: let s = str::from_utf8(bytes)?; // Parse the String to an IP address. // This only executes if the previous function call returns `Ok`. // This operation can fail as well. let addr: IpAddr = s.parse()?; // This only executes if `parse` returns `Ok`: println!("{addr:?}"); Ok(()) } fn main() -> anyhow::Result<()> { example()?; Ok(()) }
The main
function often returns a Result
as well. Rust converts it into an exit code and displays the error, if any:
//! This example demonstrates how to parse a URL and extract a portion of it. use url::Position; use url::Url; // If `parse` fails, `main` returns `Err` and the error message is displayed on // the console. fn main() -> anyhow::Result<()> { // Parse a URL. This call can fail if the URL is invalid. It early returns // via `?`: 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(()) }
For more background on error handling in Rust, review the entry point and error handling sections of this book or read this section↗ of the 'Rust book'.
A Note about Crate Representation
This book intends to cover "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
↗, the most downloaded crates (overall and per category) in crates.io
↗, most popular Rust libraries↗ and high-quality crates per lib.rs
↗ statistics↗, as well as pouring over countless blogs, forums, and examples.
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.