📖 Scenario: Imagine you are writing a small program that processes user input for a simple calculator. You want to handle errors clearly by creating your own error type.
🎯 Goal: You will create a custom error type called CalcError with two variants, then write a function that returns this error type, and finally print the error message.
📋 What You'll Learn
Create an enum called CalcError with variants DivideByZero and NegativeNumber
Implement the std::fmt::Display trait for CalcError to show user-friendly messages
Write a function calculate that takes two i32 numbers and returns Result
In calculate, return Err(CalcError::DivideByZero) if dividing by zero
Return Err(CalcError::NegativeNumber) if the first number is negative
Otherwise, return Ok with the division result
Call calculate with values 10 and 0 and print the error message
💡 Why This Matters
🌍 Real World
Custom error types help programs explain problems clearly to users or other parts of the program.
💼 Career
Understanding how to create and use custom errors is important for writing robust and maintainable Rust applications.
Progress0 / 4 steps
1
Create the custom error enum
Create an enum called CalcError with two variants: DivideByZero and NegativeNumber.
Rust
Hint
Use enum CalcError { DivideByZero, NegativeNumber } to define the error types.
2
Implement Display for CalcError
Implement the std::fmt::Display trait for CalcError to show these messages: "Cannot divide by zero" for DivideByZero and "Negative number not allowed" for NegativeNumber.
Rust
Hint
Use impl fmt::Display for CalcError and a match to return the messages.
3
Write the calculate function
Write a function called calculate that takes two i32 parameters named a and b and returns Result. Inside, return Err(CalcError::DivideByZero) if b is zero, return Err(CalcError::NegativeNumber) if a is negative, otherwise return Ok(a / b).
Rust
Hint
Use if checks and return Err or Ok accordingly.
4
Call calculate and print the error
Call the function calculate with arguments 10 and 0. Use a match to print the error message if there is an error, or print the result if successful.
Rust
Hint
Use match calculate(10, 0) and print the error with println!("Error: {}", e).
Practice
(1/5)
1. What is the main purpose of creating a custom error type in Rust?
easy
A. To automatically fix bugs in the code.
B. To make the program run faster by avoiding errors.
C. To replace the need for using Result types.
D. To describe specific problems in your program with clear error messages.
Solution
Step 1: Understand the role of custom errors
Custom error types help programmers describe specific problems clearly in their code.
Step 2: Compare with other options
Custom errors do not speed up code, fix bugs automatically, or replace Result types; they provide clear error descriptions.
Final Answer:
To describe specific problems in your program with clear error messages. -> Option D
Quick Check:
Custom error purpose = clear problem description [OK]
Hint: Custom errors explain problems clearly, not fix or speed up code [OK]
Common Mistakes:
Thinking custom errors fix bugs automatically
Confusing custom errors with performance improvements
Believing custom errors replace Result types
2. Which of the following is the correct way to start defining a custom error enum in Rust?
easy
A. enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError) }
B. struct MyError { message: String }
C. fn MyError() -> Error {}
D. class MyError { error: String }
Solution
Step 1: Identify Rust enum syntax
Rust uses enum to define custom error types with variants, like Io(std::io::Error).
Step 2: Check other options
struct is for data structures, fn is for functions, and class is not Rust syntax.
Final Answer:
enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError) } -> Option A
Quick Check:
Custom error enum = enum with variants [OK]
Hint: Custom errors use enum with variants, not struct or class [OK]
Common Mistakes:
Using struct instead of enum for error variants
Trying to define errors as functions
Using class keyword which is invalid in Rust
3. What will be the output of this Rust code snippet?
use std::fmt;
#[derive(Debug)]
enum MyError {
NotFound,
PermissionDenied,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
MyError::NotFound => write!(f, "Item not found"),
MyError::PermissionDenied => write!(f, "Permission denied"),
}
}
}
fn main() {
let err = MyError::NotFound;
println!("Error: {}", err);
}
medium
A. Error: NotFound
B. Error: Item not found
C. Error: Permission denied
D. Compilation error due to missing trait
Solution
Step 1: Understand Display implementation
The fmt method matches MyError::NotFound and writes "Item not found" to the formatter.
Step 2: Check main output
Printing err with {} uses Display, so output is "Error: Item not found".
Final Answer:
Error: Item not found -> Option B
Quick Check:
Display prints custom message = "Item not found" [OK]
A. Cannot access self.0 because enum variant is not destructured.
B. Missing implementation of Debug trait.
C. Display trait cannot be implemented for enums.
D. write! macro requires a string literal, not a variable.
Solution
Step 1: Check how self.0 is accessed
In an enum, you cannot directly access self.0 without matching or destructuring the variant.
Step 2: Understand correct pattern
You must match self to get the inner std::io::Error value before using it in write!.
Final Answer:
Cannot access self.0 because enum variant is not destructured. -> Option A
Quick Check:
Enum variant fields need matching before access [OK]
Hint: Match enum variants before accessing inner fields [OK]
Common Mistakes:
Trying to access enum fields directly without match
Thinking Display can't be implemented for enums
Assuming Debug trait is mandatory for Display
5. You want to create a custom error type that can hold either an IO error or a parsing error, and provide user-friendly messages. Which of these is the best complete approach?
hard
A. Create separate error structs for IO and parse errors without enums, and use panic! for messages.
B. Use a struct with two optional fields for IO and parse errors, and implement Display only.
C. Define an enum with variants for each error type, implement Display with match arms for messages, and implement std::error::Error.
D. Use a type alias for Result with String errors and skip custom error types.
Solution
Step 1: Choose enum for multiple error types
An enum cleanly groups different error variants like IO and parse errors.
Step 2: Implement Display and std::error::Error traits
Display provides friendly messages; implementing std::error::Error integrates with Rust error handling.
Final Answer:
Define an enum with variants for each error type, implement Display with match arms for messages, and implement std::error::Error. -> Option C