Implement expect for Option and Result in Rust
In Rust, unwrapping Option and Result types often involves using unwrap(), which can panic with a generic error message if the value is None or Err. This makes debugging difficult. The expect() method provides a more helpful alternative by allowing you to specify a custom panic message, which is invaluable for understanding the cause of a failure during development. This challenge will guide you through implementing this essential functionality yourself.
Problem Description
Your task is to create two macros, option_expect and result_expect, that mimic the behavior of Option::expect and Result::expect respectively. These macros should take two arguments: the value to unwrap (an Option or Result) and a string literal representing the panic message.
Key Requirements:
option_expectMacro:- Takes an
Option<T>and a&'static str(the panic message). - If the
OptionisSome(v), it should return the inner valuev. - If the
OptionisNone, it should panic with the provided message.
- Takes an
result_expectMacro:- Takes a
Result<T, E>and a&'static str(the panic message). - If the
ResultisOk(v), it should return the inner valuev. - If the
ResultisErr(e), it should panic with the provided message.
- Takes a
Expected Behavior:
When the Option is Some or the Result is Ok, the macro should behave like unwrap(). When the Option is None or the Result is Err, the macro should panic with the specific message provided.
Edge Cases:
- Consider the types of the inner values in
OptionandResult. The macros should be generic enough to handle any type. - The panic message must be a string literal (
&'static str).
Examples
Example 1: option_expect with Some
let value: Option<i32> = Some(42);
let unwrapped = option_expect!(value, "Expected a number, but got None");
// unwrapped will be 42
Explanation: The Option contains Some(42). option_expect extracts the inner value 42.
Example 2: option_expect with None (Panic)
let value: Option<i32> = None;
let unwrapped = option_expect!(value, "Expected a number, but got None");
// This line will panic with the message: "Expected a number, but got None"
Explanation: The Option is None. option_expect triggers a panic with the provided message.
Example 3: result_expect with Ok
let res: Result<String, std::io::Error> = Ok(String::from("Hello"));
let unwrapped = result_expect!(res, "Expected a string, but got an IO error");
// unwrapped will be String::from("Hello")
Explanation: The Result is Ok("Hello"). result_expect returns the inner string.
Example 4: result_expect with Err (Panic)
use std::io::{self, ErrorKind};
let res: Result<String, io::Error> = Err(io::Error::new(ErrorKind::NotFound, "File not found"));
let unwrapped = result_expect!(res, "Failed to read file");
// This line will panic with the message: "Failed to read file: File not found"
// (The specific error message from io::Error might also be appended by the default panic handler)
Explanation: The Result is Err. result_expect triggers a panic with the provided message.
Constraints
- The macros must be implemented using Rust's
macro_rules!syntax. - The panic message must be a string literal (
&'static str). - The macros should be as generic as possible, working with any
TinOption<T>and anyT,EinResult<T, E>. - The macros should return the unwrapped value directly, not a reference unless the original
Option/Resultcontained a reference.
Notes
- Remember that
macro_rules!allows you to define patterns and transformations. - You'll need to use the
panic!macro internally. - Consider how to handle the different variants of
OptionandResultwithin your macro rules. - The goal is to replicate the core functionality and error-handling behavior of the standard library's
expectmethods.