mirror of
https://github.com/leonardomso/rust-skills.git
synced 2026-09-14 19:33:21 +08:00
0016d5cfb2
Includes rules for: - Ownership and borrowing patterns - Error handling with thiserror/anyhow - Memory management and allocation - API design following Rust guidelines - Async/Tokio patterns - Performance optimization - Naming conventions - Type safety - Testing strategies - Documentation standards - Project structure - Linting configuration - Common anti-patterns to avoid
3.2 KiB
3.2 KiB
doc-question-mark
Use
?in examples, not.unwrap()
Why It Matters
Doc examples should model best practices. Using .unwrap() teaches users to ignore errors, while ? demonstrates proper error propagation. Examples with ? also fail the doctest if an error occurs, catching bugs in documentation.
Rust doctests wrap examples in a function that returns Result<(), E> by default when you use ?, making this pattern easy to adopt.
Bad
/// Reads a configuration file.
///
/// # Examples
///
/// ```
/// let config = Config::from_file("config.toml").unwrap();
/// println!("{:?}", config.database_url);
/// ```
pub fn from_file(path: &str) -> Result<Config, Error> {
// ...
}
/// Fetches data from the API.
///
/// # Examples
///
/// ```
/// let client = Client::new();
/// let response = client.get("https://api.example.com").unwrap();
/// let data: Data = response.json().unwrap();
/// ```
pub async fn get(&self, url: &str) -> Result<Response, Error> {
// ...
}
Good
/// Reads a configuration file.
///
/// # Examples
///
/// ```
/// # use my_crate::{Config, Error};
/// # fn main() -> Result<(), Error> {
/// let config = Config::from_file("config.toml")?;
/// println!("{:?}", config.database_url);
/// # Ok(())
/// # }
/// ```
pub fn from_file(path: &str) -> Result<Config, Error> {
// ...
}
/// Fetches data from the API.
///
/// # Examples
///
/// ```no_run
/// # use my_crate::{Client, Data, Error};
/// # async fn example() -> Result<(), Error> {
/// let client = Client::new();
/// let response = client.get("https://api.example.com").await?;
/// let data: Data = response.json().await?;
/// # Ok(())
/// # }
/// ```
pub async fn get(&self, url: &str) -> Result<Response, Error> {
// ...
}
Doctest Wrapper Pattern
Rust wraps doc examples in a function. You can make this explicit:
/// # Examples
///
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let value = parse_config("key=value")?;
/// assert_eq!(value.key, "value");
/// # Ok(())
/// # }
/// ```
Or use the implicit wrapper (Rust 2021+):
/// # Examples
///
/// ```
/// # use my_crate::parse_config;
/// let value = parse_config("key=value")?;
/// assert_eq!(value.key, "value");
/// # Ok::<(), my_crate::Error>(())
/// ```
When to Use .unwrap()
There are specific cases where .unwrap() is acceptable in examples:
/// # Examples
///
/// ```
/// // Static regex that is known at compile time to be valid
/// let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap();
///
/// // Parsing a literal that cannot fail
/// let n: i32 = "42".parse().unwrap();
/// ```
But still prefer ? when demonstrating error handling patterns.
Comparison
| Pattern | Behavior on Error | Teaches |
|---|---|---|
.unwrap() |
Panics with generic message | Bad habits |
.expect() |
Panics with custom message | Slightly better |
? |
Propagates error, test fails | Best practices |
See Also
- doc-examples-section - Writing examples
- doc-hidden-setup - Hiding setup code
- err-question-mark - Error propagation