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.1 KiB
3.1 KiB
doc-panics-section
Include
# Panicssection for functions that can panic
Why It Matters
Panics are exceptional conditions that crash the program (or unwind the stack). Users need to know when a function might panic so they can ensure preconditions are met or avoid the function in contexts where panics are unacceptable (e.g., no_std, embedded, FFI).
If a function can panic, document exactly when.
Bad
/// Returns the element at the given index.
pub fn get(index: usize) -> &T {
&self.data[index] // Panics if out of bounds - not documented!
}
/// Divides two numbers.
pub fn divide(a: i32, b: i32) -> i32 {
a / b // Panics on division by zero - not documented!
}
Good
/// Returns the element at the given index.
///
/// # Panics
///
/// Panics if `index` is out of bounds (i.e., `index >= self.len()`).
///
/// # Examples
///
/// ```
/// let v = vec![1, 2, 3];
/// assert_eq!(v.get(1), &2);
/// ```
pub fn get(&self, index: usize) -> &T {
&self.data[index]
}
/// Divides two numbers.
///
/// # Panics
///
/// Panics if `divisor` is zero.
///
/// For a non-panicking version, use [`checked_divide`].
pub fn divide(dividend: i32, divisor: i32) -> i32 {
dividend / divisor
}
/// Divides two numbers, returning `None` if the divisor is zero.
pub fn checked_divide(dividend: i32, divisor: i32) -> Option<i32> {
if divisor == 0 {
None
} else {
Some(dividend / divisor)
}
}
Common Panic Conditions
| Operation | Panic Condition |
|---|---|
Index access [i] |
Index out of bounds |
Division /, % |
Division by zero |
.unwrap() |
None or Err value |
.expect() |
None or Err value |
slice::split_at(mid) |
mid > len |
Vec::remove(i) |
i >= len |
| Overflow (debug) | Integer overflow |
Pattern: Panic vs Return Error
Document why you chose to panic vs return Result:
/// Creates a new buffer with the given capacity.
///
/// # Panics
///
/// Panics if `capacity` is zero. A buffer must have at least
/// one byte of capacity.
///
/// This panics rather than returning an error because a zero-capacity
/// buffer represents a programming error, not a runtime condition.
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0, "capacity must be non-zero");
// ...
}
Pattern: Debug-Only Panics
/// Adds an item to the collection.
///
/// # Panics
///
/// In debug builds, panics if the collection is at capacity.
/// In release builds, this is a no-op when at capacity.
pub fn push(&mut self, item: T) {
debug_assert!(self.len < self.capacity, "collection at capacity");
// ...
}
Provide Non-Panicking Alternatives
When documenting a panicking function, point to safe alternatives:
/// # Panics
///
/// Panics if the index is out of bounds.
///
/// For a non-panicking version, use [`get`] which returns `Option<&T>`.
See Also
- doc-errors-section - Documenting errors
- doc-safety-section - Documenting unsafe
- err-result-over-panic - Preferring Result