Systems programming provides the foundation for the world's computation. Writing performance-sensitive code requires a programming language that puts programmers in control of how memory, processor time, and other system resources are used. The Rust systems programming language combines that control with a modern type system that catches broad classes of common mistakes, from memory management errors to data races between threads.
With this practical guide, experienced systems programmers will learn how to successfully bridge the gap between performance and safety using Rust. Jim Blandy, Jason Orendorff, and Leonora Tindall demonstrate how Rust's features put programmers in control over memory consumption and processor use by combining predictable performance with memory safety and trustworthy concurrency.
You'll learn:
- Rust's fundamental data types and the core concepts of ownership and borrowing
- How to write flexible, efficient code with traits and generics
- How to write fast, multithreaded code without data races
- Rust's key power tools: closures, iterators, and asynchronous programming
- Collections, strings and text, input and output, macros, unsafe code, and foreign function interfaces
This revised, updated edition covers the Rust 2021 Edition.
Author(s): Jim Blandy, Jason Orendorff, Leonora Tindall
Edition: 2
Publisher: O'Reilly Media
Year: 2021
Language: English
Pages: 735
Tags: rust
Cover
Copyright
Table of Contents
Preface
Who Should Read This Book
Why We Wrote This Book
Navigating This Book
Conventions Used in This Book
Using Code Examples
O’Reilly Online Learning
How to Contact Us
Acknowledgments
Chapter 1. Systems Programmers Can Have Nice Things
Rust Shoulders the Load for You
Parallel Programming Is Tamed
And Yet Rust Is Still Fast
Rust Makes Collaboration Easier
Chapter 2. A Tour of Rust
rustup and Cargo
Rust Functions
Writing and Running Unit Tests
Handling Command-Line Arguments
Serving Pages to the Web
Concurrency
What the Mandelbrot Set Actually Is
Parsing Pair Command-Line Arguments
Mapping from Pixels to Complex Numbers
Plotting the Set
Writing Image Files
A Concurrent Mandelbrot Program
Running the Mandelbrot Plotter
Safety Is Invisible
Filesystems and Command-Line Tools
The Command-Line Interface
Reading and Writing Files
Find and Replace
Chapter 3. Fundamental Types
Fixed-Width Numeric Types
Integer Types
Checked, Wrapping, Saturating, and Overflowing Arithmetic
Floating-Point Types
The bool Type
Characters
Tuples
Pointer Types
References
Boxes
Raw Pointers
Arrays, Vectors, and Slices
Arrays
Vectors
Slices
String Types
String Literals
Byte Strings
Strings in Memory
String
Using Strings
Other String-Like Types
Type Aliases
Beyond the Basics
Chapter 4. Ownership and Moves
Ownership
Moves
More Operations That Move
Moves and Control Flow
Moves and Indexed Content
Copy Types: The Exception to Moves
Rc and Arc: Shared Ownership
Chapter 5. References
References to Values
Working with References
Rust References Versus C++ References
Assigning References
References to References
Comparing References
References Are Never Null
Borrowing References to Arbitrary Expressions
References to Slices and Trait Objects
Reference Safety
Borrowing a Local Variable
Receiving References as Function Arguments
Passing References to Functions
Returning References
Structs Containing References
Distinct Lifetime Parameters
Omitting Lifetime Parameters
Sharing Versus Mutation
Taking Arms Against a Sea of Objects
Chapter 6. Expressions
An Expression Language
Precedence and Associativity
Blocks and Semicolons
Declarations
if and match
if let
Loops
Control Flow in Loops
return Expressions
Why Rust Has loop
Function and Method Calls
Fields and Elements
Reference Operators
Arithmetic, Bitwise, Comparison, and Logical Operators
Assignment
Type Casts
Closures
Onward
Chapter 7. Error Handling
Panic
Unwinding
Aborting
Result
Catching Errors
Result Type Aliases
Printing Errors
Propagating Errors
Working with Multiple Error Types
Dealing with Errors That “Can’t Happen”
Ignoring Errors
Handling Errors in main()
Declaring a Custom Error Type
Why Results?
Chapter 8. Crates and Modules
Crates
Editions
Build Profiles
Modules
Nested Modules
Modules in Separate Files
Paths and Imports
The Standard Prelude
Making use Declarations pub
Making Struct Fields pub
Statics and Constants
Turning a Program into a Library
The src/bin Directory
Attributes
Tests and Documentation
Integration Tests
Documentation
Doc-Tests
Specifying Dependencies
Versions
Cargo.lock
Publishing Crates to crates.io
Workspaces
More Nice Things
Chapter 9. Structs
Named-Field Structs
Tuple-Like Structs
Unit-Like Structs
Struct Layout
Defining Methods with impl
Passing Self as a Box, Rc, or Arc
Type-Associated Functions
Associated Consts
Generic Structs
Structs with Lifetime Parameters
Deriving Common Traits for Struct Types
Interior Mutability
Chapter 10. Enums and Patterns
Enums
Enums with Data
Enums in Memory
Rich Data Structures Using Enums
Generic Enums
Patterns
Literals, Variables, and Wildcards in Patterns
Tuple and Struct Patterns
Array and Slice Patterns
Reference Patterns
Match Guards
Matching Multiple Possibilities
Binding with @ Patterns
Where Patterns Are Allowed
Populating a Binary Tree
The Big Picture
Chapter 11. Traits and Generics
Using Traits
Trait Objects
Generic Functions and Type Parameters
Which to Use
Defining and Implementing Traits
Default Methods
Traits and Other People’s Types
Self in Traits
Subtraits
Type-Associated Functions
Fully Qualified Method Calls
Traits That Define Relationships Between Types
Associated Types (or How Iterators Work)
Generic Traits (or How Operator Overloading Works)
impl Trait
Associated Consts
Reverse-Engineering Bounds
Traits as a Foundation
Chapter 12. Operator Overloading
Arithmetic and Bitwise Operators
Unary Operators
Binary Operators
Compound Assignment Operators
Equivalence Comparisons
Ordered Comparisons
Index and IndexMut
Other Operators
Chapter 13. Utility Traits
Drop
Sized
Clone
Copy
Deref and DerefMut
Default
AsRef and AsMut
Borrow and BorrowMut
From and Into
TryFrom and TryInto
ToOwned
Borrow and ToOwned at Work: The Humble Cow
Chapter 14. Closures
Capturing Variables
Closures That Borrow
Closures That Steal
Function and Closure Types
Closure Performance
Closures and Safety
Closures That Kill
FnOnce
FnMut
Copy and Clone for Closures
Callbacks
Using Closures Effectively
Chapter 15. Iterators
The Iterator and IntoIterator Traits
Creating Iterators
iter and iter_mut Methods
IntoIterator Implementations
from_fn and successors
drain Methods
Other Iterator Sources
Iterator Adapters
map and filter
filter_map and flat_map
flatten
take and take_while
skip and skip_while
peekable
fuse
Reversible Iterators and rev
inspect
chain
enumerate
zip
by_ref
cloned, copied
cycle
Consuming Iterators
Simple Accumulation: count, sum, product
max, min
max_by, min_by
max_by_key, min_by_key
Comparing Item Sequences
any and all
position, rposition, and ExactSizeIterator
fold and rfold
try_fold and try_rfold
nth, nth_back
last
find, rfind, and find_map
Building Collections: collect and FromIterator
The Extend Trait
partition
for_each and try_for_each
Implementing Your Own Iterators
Chapter 16. Collections
Overview
Vec
Accessing Elements
Iteration
Growing and Shrinking Vectors
Joining
Splitting
Swapping
Sorting and Searching
Comparing Slices
Random Elements
Rust Rules Out Invalidation Errors
VecDeque
BinaryHeap
HashMap and BTreeMap
Entries
Map Iteration
HashSet and BTreeSet
Set Iteration
When Equal Values Are Different
Whole-Set Operations
Hashing
Using a Custom Hashing Algorithm
Beyond the Standard Collections
Chapter 17. Strings and Text
Some Unicode Background
ASCII, Latin-1, and Unicode
UTF-8
Text Directionality
Characters (char)
Classifying Characters
Handling Digits
Case Conversion for Characters
Conversions to and from Integers
String and str
Creating String Values
Simple Inspection
Appending and Inserting Text
Removing and Replacing Text
Conventions for Searching and Iterating
Patterns for Searching Text
Searching and Replacing
Iterating over Text
Trimming
Case Conversion for Strings
Parsing Other Types from Strings
Converting Other Types to Strings
Borrowing as Other Text-Like Types
Accessing Text as UTF-8
Producing Text from UTF-8 Data
Putting Off Allocation
Strings as Generic Collections
Formatting Values
Formatting Text Values
Formatting Numbers
Formatting Other Types
Formatting Values for Debugging
Formatting Pointers for Debugging
Referring to Arguments by Index or Name
Dynamic Widths and Precisions
Formatting Your Own Types
Using the Formatting Language in Your Own Code
Regular Expressions
Basic Regex Use
Building Regex Values Lazily
Normalization
Normalization Forms
The unicode-normalization Crate
Chapter 18. Input and Output
Readers and Writers
Readers
Buffered Readers
Reading Lines
Collecting Lines
Writers
Files
Seeking
Other Reader and Writer Types
Binary Data, Compression, and Serialization
Files and Directories
OsStr and Path
Path and PathBuf Methods
Filesystem Access Functions
Reading Directories
Platform-Specific Features
Networking
Chapter 19. Concurrency
Fork-Join Parallelism
spawn and join
Error Handling Across Threads
Sharing Immutable Data Across Threads
Rayon
Revisiting the Mandelbrot Set
Channels
Sending Values
Receiving Values
Running the Pipeline
Channel Features and Performance
Thread Safety: Send and Sync
Piping Almost Any Iterator to a Channel
Beyond Pipelines
Shared Mutable State
What Is a Mutex?
Mutex
mut and Mutex
Why Mutexes Are Not Always a Good Idea
Deadlock
Poisoned Mutexes
Multiconsumer Channels Using Mutexes
Read/Write Locks (RwLock)
Condition Variables (Condvar)
Atomics
Global Variables
What Hacking Concurrent Code in Rust Is Like
Chapter 20. Asynchronous Programming
From Synchronous to Asynchronous
Futures
Async Functions and Await Expressions
Calling Async Functions from Synchronous Code: block_on
Spawning Async Tasks
Async Blocks
Building Async Functions from Async Blocks
Spawning Async Tasks on a Thread Pool
But Does Your Future Implement Send?
Long Running Computations: yield_now and spawn_blocking
Comparing Asynchronous Designs
A Real Asynchronous HTTP Client
An Asynchronous Client and Server
Error and Result Types
The Protocol
Taking User Input: Asynchronous Streams
Sending Packets
Receiving Packets: More Asynchronous Streams
The Client’s Main Function
The Server’s Main Function
Handling Chat Connections: Async Mutexes
The Group Table: Synchronous Mutexes
Chat Groups: tokio’s Broadcast Channels
Primitive Futures and Executors: When Is a Future Worth Polling Again?
Invoking Wakers: spawn_blocking
Implementing block_on
Pinning
The Two Life Stages of a Future
Pinned Pointers
The Unpin Trait
When Is Asynchronous Code Helpful?
Chapter 21. Macros
Macro Basics
Basics of Macro Expansion
Unintended Consequences
Repetition
Built-In Macros
Debugging Macros
Building the json! Macro
Fragment Types
Recursion in Macros
Using Traits with Macros
Scoping and Hygiene
Importing and Exporting Macros
Avoiding Syntax Errors During Matching
Beyond macro_rules!
Chapter 22. Unsafe Code
Unsafe from What?
Unsafe Blocks
Example: An Efficient ASCII String Type
Unsafe Functions
Unsafe Block or Unsafe Function?
Undefined Behavior
Unsafe Traits
Raw Pointers
Dereferencing Raw Pointers Safely
Example: RefWithFlag
Nullable Pointers
Type Sizes and Alignments
Pointer Arithmetic
Moving into and out of Memory
Example: GapBuffer
Panic Safety in Unsafe Code
Reinterpreting Memory with Unions
Matching Unions
Borrowing Unions
Chapter 23. Foreign Functions
Finding Common Data Representations
Declaring Foreign Functions and Variables
Using Functions from Libraries
A Raw Interface to libgit2
A Safe Interface to libgit2
Conclusion
Index
About the Authors
Colophon