Rust: Result, Traits and Derivations

Error Handling in Rust

  • Rust distinguishes between recoverable and unrecoverable errors.
  • Recoverable errors: handled with Result<T, E>. These can be predicted and recovered from.
  • Unrecoverable errors: handled with the panic! macro. These should stop the program to prevent further issues.

Unrecoverable Errors with panic!

  • panic! terminates the program and displays an error message.
  • Use panic! for:
    • Invalid program state (e.g., negative health).
    • Critical resource failures (e.g., memory allocation).
    • Bugs or logical errors.
  • Can configure to abort on panic instead of unwinding the stack to reduce binary size.

Recoverable Errors with Result<T, E>

  • Result<T, E> enum represents either success (Ok(T)) or failure (Err(E)).
  • T: Type of the value returned on success.
  • E: Type of the error returned on failure.
  • Handle Result with match for Ok and Err cases.
  • Use the ? operator to propagate errors to the caller.
  • unwrap returns the value inside Ok or panics if it’s Err.
  • expect is like unwrap but allows a custom panic message.
  • and_then chains operations that return Result; any failure stops the chain.
  • Use Result for recoverable errors like file I/O, network requests, or user input validation.

Custom Error Types

  • Custom error types provide better error handling and context.

  • Implemented using enums or structs.

  • Example (enum):

    #[derive(Debug)]
    enum MyError {
        FileNotFound,
        PermissionDenied,
        InvalidData,
    }
    
  • Example (struct):

    #[derive(Debug)]
    struct ParseError {
        message: String,
        line: u32,
        column: u32,
    }
    

Traits

  • Traits define shared behavior across types, enabling code reuse and polymorphism.

  • Define method signatures that implementing types must provide.

  • Traits can provide default implementations.

  • Example:

    pub trait Summary {
        fn summarize(&self) -> String;
    }
    
  • Use impl Trait syntax for accepting or returning types that implement a trait.

  • Trait bounds (<T: Summary>) specify that a generic type must implement a trait.

  • Multiple trait bounds can be combined using +.

The Error Trait

  • Implementing the Error trait (from std::error::Error) allows custom errors to be compatible with libraries expecting Error types.
  • Also implement fmt::Display for a human-readable description.