When implementing error handling, balance between propagation and recovery. Design error types to preserve context while providing users with meaningful ways to handle failure.
For error propagation:
std::error::Error
trait, including source()
method for error chainingResult<usize>
over Result<()>
when position information is needed)Send + Sync
error types when errors might cross thread boundariesFor recovery paths:
// Poor: May panic unexpectedly and loses context
let pos = std.stream_position().unwrap();
// Better: Provides fallback and preserves error context
let pos = std.stream_position().unwrap_or(0);
// Poor: Error type lacks context and proper trait implementation
struct MyError(());
// Better: Full featured error with context preservation
struct MyError<T> {
inner: T,
cause: io::Error,
}
impl<T> std::error::Error for MyError<T> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.cause)
}
}
// Even in examples, show proper error handling
// Poor: Ignores errors
let _ = compress_data(reader).await;
// Better: Shows proper error handling
compress_data(reader).await?;
Enter the URL of a public GitHub repository