Everything you ever wanted to know about Rust...
...but didn't know where to ask. Rust is designed to be a flexible language, one that will let you do just about anything. This is a good thing. But it also means that learning to use Rust means developing a sense for which features and patterns to use where. This book is designed to help you "shortcircuit" that process by collecting expert answers and advice to common questions that come up when building Rust software.
Want to help improve this guide?
This book is community maintained and we need your help to make it better!
- If you have questions you'd like to see answered, open an issue on the github repo.
- If you'd like to answer a new question, or improve an answer, open a pull request.
When to use Rust?
Like most general programming languages, Rust can be used for virtually any kind of project. This can make it difficult to know when to use it! Here are a few criteria.
Rust is designed for programs and projects where
- performance and/or memory usage;
- reliability; and
- long-term maintaince
are top considerations. If your program fits these criteria, then Rust would probably be a good choice.
What are great domains for Rust?
Domains where Rust can be a particularly good fit:
- Systems programing, low-level development, or embedded systems;
- Network systems, where Rust offers "predictably low" tail latency, low memory usage, and high reliability;
- Developer tools and CLI applications, where Rust's can snappy response time and getting the right answer is super important.
When not to use Rust?
When there's a better option, of course! Here are some reasons you might prefer not to use Rust
- you want to make use of a library or framework in another language;
- you're targeting an environment or community where the other language is the default choice (e.g., Swift for iOS);
- rapid iteration is more important than getting the details right;
- you want to learn something else or you just really like the other language. That's cool too.
When to use references (&T
)
References are Rust's superpower -- but if they are used too much, they can also be a super pain in the neck.
How many lifetime parameters?
When not to borrow
Vector and indices
The "vector and index" pattern is a very simple way to model virtually any kind of data structure, particularly those with cycles or other shapes that don't fit Rust's .
Short description
- For each node, create two types
- A
struct Node(usize)
representing references to a node via a vector index - A
struct NodeData { ..., link: Node }
representing the data in a node
- A
- Store your graph
struct Graph { nodes: Vec<NodeData> }
with- accessors for node data
fn edge(&self, node: Node) -> &NodeData { &self.nodes[node.0] }
fn edge_mut(&mut self, node: Node) -> &mut NodeData { &mut self.nodes[node.0] }
- accessors for node data
When it works well
- When you mainly add things to your graph, not remove them
- When you want to share your graph in a read-only fashion across threads, but be able to mutate it when not shared
When it works less well
- You have a long-lived graph where you will be adding and removing nodes over time
- Because
Alternatives and ways to make it safer
References
Crates
Real-world examples of this pattern in use
Blog posts
Ref-counting
When to use enums?
Usually. :)
Designing traits
Generics vs associated types
Handling errors
When to use async I/O vs sync I/O?
Choosing and configuring your executor
Work stealing
Thread per core
Choosing and configuring your executor
Work stealing
Thread per core
Intrusive linked list
TBD