Rust
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Ownership and Borrowing
-
Section 4: Structuring Data
-
Section 5: Collections and Error Handling
-
Section 6: Traits and Generics
-
Section 7: Concurrency
-
Section 8: Building for the Web
-
Section 9: Memory and Performance
-
Section 10: More Standard Library and Ecosystem
-
Section 11: Advanced Rust
-
Section 12: Rust for Systems and WebAssembly
-
Section 13: Tooling and Best Practices
-
Section 14: Data Structures and Algorithms in Rust
-
Section 15: Practical Projects
-
Section 16: Interview Practice
-
Section 17: std::collections In Depth
-
Section 18: std::io and std::fs In Depth
-
Section 19: std::net
-
Section 20: std::option and std::result In Depth
-
Section 21: std::iter In Depth
-
Section 22: std::sync In Depth
-
Section 23: std::string and std::str
-
Section 24: Cargo and Crates.io Ecosystem
-
Section 25: Popular Crates Ecosystem
-
Section 26: Rust Memory Model Deep Dive
-
Section 27: More Practice Exercises
-
Section 28: More Interview Practice
-
Section 29: Async Rust Deep Dive
-
Section 30: Tokio Ecosystem In Depth
-
Section 31: Error Handling Ecosystem Deep Dive
-
Section 32: Serde In Depth
-
Section 33: Web Development with Rust Deep Dive
-
Section 34: Database Access Ecosystem
-
Section 35: Rust for Embedded Systems Deep Dive
-
Section 36: Rust Macros In Depth
-
Section 37: Advanced Trait System
-
Section 38: Unsafe Rust In Depth
-
Section 39: Rust CLI Development
-
Section 40: Testing Ecosystem Deep Dive
-
Section 41: WebAssembly Deep Dive
-
Section 42: Rust Design Patterns
-
Section 43: More Data Structures in Rust
-
Section 44: Final Practice Projects
-
Section 45: Rust Performance Optimization
-
Section 46: Rust Ecosystem Tooling
-
Section 47: More Interview and Review
11: Comments and Documentation
I've spent a lot of time reviewing pull requests over the years, and there is one specific habit that always makes me sigh: the "obvious comment." You know the ones. A developer writes a line of code, and then writes a comment right above it that simply translates the code into English. It doesn't add value; it just adds noise.
The trap of redundant explanations
Imagine you're writing a utility to handle API retries. You might be tempted to write something like this:
// Calculate the delay using exponential backoff
let delay = 2u64.pow(attempt);
// Multiply by the base multiplier
let final_delay = delay * base_ms;
If you're a Rust developer, you can already see exactly what's happening. Telling me that you're "calculating the delay" when the variable is named delay is a waste of your time and mine. When I see this in a codebase, it's a red flag that the author is using comments as a crutch because they aren't trusting their naming conventions. This is the naive way of documenting: treating comments as a narrative of the what.
Shifting to the "Why" and the "How to Use"
In Rust, we have a much better way to handle this. I want you to distinguish between // (regular comments) and /// (documentation comments). Regular comments are for the people maintaining the internals of the function—the "why did I use this weird workaround here?" notes. Documentation comments are for the people using your function.
Instead of describing the math inside the function, use a doc comment to describe the contract. Let's rewrite that backoff logic:
/// Calculates the wait time before a retry attempt.
///
/// The delay grows exponentially based on the attempt number to avoid
/// overwhelming the server (thundering herd problem).
///
/// # Examples
///
/// ```
/// let delay = calculate_backoff(3, 100);
/// assert_eq!(delay, 800);
/// ```
pub fn calculate_backoff(attempt: u32, base_ms: u64) -> u64 {
2u64.pow(attempt) * base_ms
}
See the difference? I'm not explaining the pow() call; I'm explaining the intent (preventing the thundering herd problem) and providing a concrete example of how it behaves. The best part is that those examples aren't just for show—they are "doc-tests." When you run cargo test, Rust actually compiles and runs the code inside those triple-slash comments to ensure your documentation never goes out of date. If you change the logic but forget to update the example, your build fails. That's a safety net you don't get in most other languages.
Context at the top of the file
Sometimes you need to describe the entire module rather than a single function. If you put /// at the top of a file, it attaches to the first item it finds. To document the module itself, you use //!. I like to think of the exclamation mark as saying, "This applies to the container I'm currently inside."
I usually use module-level docs to explain the architectural role of the file. For instance, if this backoff logic lived in a retry.rs file, I'd start the file with:
//! This module provides primitives for handling transient network failures.
//!
//! It includes strategies for exponential backoff and jitter to ensure
//! stable recovery during system outages.
By splitting your comments this way, you create a tiered information system. A user can run cargo doc --open and get a beautiful, searchable website that tells them exactly how to use your API without ever having to look at your implementation details. You're effectively separating the "User Manual" from the "Maintenance Log."
📋 Practical Task
Documenting a Thread-Safe Cache Manager
You have been handed a piece of legacy code for a simple CacheManager. The code works perfectly, but it's a "black box"—no one knows how to use it without reading every line of implementation. Your task is to transform this into a professional, documented library.
pub struct CacheManager {
storage: std::collections::HashMap<String, String>,
}
impl CacheManager {
pub fn new() -> Self {
Self { storage: std::collections::HashMap::new() }
}
pub fn set(&mut self, key: String, value: String) {
self.storage.insert(key, value);
}
pub fn get(&self, key: &str) -> Option<String> {
self.storage.get(key).cloned()
}
}
Requirements:
- Add a module-level documentation block (
//!) explaining that this manager provides a simple key-value store for string data. - Add documentation comments (
///) to thesetandgetmethods. - Include a
# Examplessection in thegetmethod's documentation that demonstrates both a successful cache hit and a cache miss (usingassert_eq!). - Ensure that the comments focus on the behavior (e.g., what happens when a key doesn't exist) rather than just repeating the function name.
There are no comments for now.