Result is Rust’s enum for computations that either succeed with Ok(value) or fail with Err(error). By making failure a value in the return type, it documents possible failure cases and requires callers to acknowledge them rather than following an exception-like hidden control path. section 7.4 section 7.3
Use Result for ordinary, expected failures such as invalid customer state or unavailable stock. Reserve panic for conditions that should be impossible, unrecoverable startup failures, or assumptions already validated; use expect with a reason when a panic is deliberately retained. section 7.4 section 7.12
fn calculate_answer_to_life() -> Either<i32> {
Either::Success(42)
}
fn main() {
match calculate_answer_to_life() {
Either::Success(answer) => {
println!("Got the answer: {answer}");
}
Either::Failure(_) => {
println!("Should handle failure");
}
}
}
A small Either enum illustrates the shape Result provides: one variant carries success, another carries failure, and match handles both outcomes. section 7.3
A Result-based API makes error handling explicit through several practical moves:
- Return Result<Output, Error> so a function signature records that it can fail. section 7.4
- Wrap a successful final value in Ok after changing a function’s return type. section 7.7
- Replace a recognized panic path with return Err(message) so the error matches the declared Result type. section 7.8.1
- Test success with unwrap when the fixture must succeed, and test failure with expect_err. section 7.7 section 7.8.1
Result also composes with transformations. A success-only map operation can change the contained value while preserving failure, with pattern matching providing the underlying case analysis. This makes the success and error paths visible in both types and control flow. section 7.3
Converting a panicking function
An attribute macro can change a function returning Person into one returning Result<Person, String>, wrap its final Person in Ok, and rewrite selected panic! calls inside an if expression as return Err(message.to_string()). This implementation is intentionally partial: it does not yet cover every return expression or every expression form containing a panic. section 7.7 section 7.8.1
When Result is used inside a procedural macro, distinguish errors in the macro crate from errors in generated code. cargo check can validate the macro while generated output still fails; cargo expand helps reveal the expansion. A missing return before Err can leave Result’s success type unconstrained. section 7.8.2
For macro validation, return Result<..., syn::Error> internally and convert an Err into compile errors at the entrypoint. syn::Error can attach a message to a source span, and combined errors can report more than one invalid condition at once. section 7.9.1 section 7.12







