📖 Scenario: You are building a simple Rust program that reads a username from a file and prints a greeting. Handling errors properly is important to make your program reliable and user-friendly.
🎯 Goal: Learn how to handle errors in Rust using Result, match, and the ? operator to write clean and safe code.
📋 What You'll Learn
Create a function to read a username from a file
Use a configuration variable for the filename
Handle errors using match and Result
Use the ? operator for error propagation
Print the greeting or an error message
💡 Why This Matters
🌍 Real World
Reading configuration or user data from files is common in many programs. Handling errors properly prevents crashes and helps users understand what went wrong.
💼 Career
Rust developers must write safe and reliable code. Understanding error handling with Result, match, and the ? operator is essential for building robust applications.
Progress0 / 4 steps
1
DATA SETUP: Create a function to read username from a file
Write a function called read_username that returns a Result. Inside, use std::fs::read_to_string to read from a file named "user.txt" and return the content.
Rust
Hint
Use std::fs::read_to_string("user.txt") to read the file content and return it directly.
2
CONFIGURATION: Add a variable for the filename
Create a variable called filename and set it to "user.txt". Update the read_username function to use this filename variable instead of the hardcoded string.
Rust
Hint
Define filename outside the function and use it inside read_username.
3
CORE LOGIC: Use match to handle errors when calling read_username
Call read_username() and use a match statement with variables username and error to handle the Ok and Err cases. In Ok, print "Hello, {username}!". In Err, print "Failed to read username: {error}".
Rust
Hint
Use match result with Ok(username) and Err(error) arms to print messages.
4
OUTPUT: Use the ? operator in read_username and print the greeting in main
Rewrite read_username to use the ? operator for error propagation. Then, in main, call read_username() and use match with variables username and error to print "Hello, {username}!" or "Failed to read username: {error}".
Rust
Hint
Use ? operator inside read_username to return errors quickly. Then handle the result in main with match.
Make sure the file user.txt contains Alice for testing.
Practice
(1/5)
1. What is the primary purpose of using Result in Rust error handling?
easy
A. To convert a string into a number
B. To represent either success or failure of an operation
C. To define a constant value in the program
D. To create a new thread for parallel execution
Solution
Step 1: Understand the role of Result
Result is an enum used to represent either success (Ok) or failure (Err) in Rust operations.
Step 2: Identify the purpose in error handling
It helps safely handle errors by forcing the programmer to consider both success and failure cases explicitly.
Final Answer:
To represent either success or failure of an operation -> Option B
Quick Check:
Result = success or failure [OK]
Hint: Result means success or error outcome [OK]
Common Mistakes:
Confusing Result with threading or constants
Thinking Result automatically fixes errors
Using Result only for numbers or strings
2. Which of the following is the correct syntax to use the ? operator in a function that returns Result<T, E>?
easy
A. let value = some_function()?;
B. let value = some_function!();
C. let value = some_function();?
D. let value = ?some_function();
Solution
Step 1: Recall the ? operator usage
The ? operator is placed immediately after a function call that returns a Result to propagate errors easily.
Step 2: Check syntax correctness
let value = some_function()?; correctly places ? after the function call: some_function()?. Other options misuse the operator placement.
Final Answer:
let value = some_function()?; -> Option A
Quick Check:
? goes right after function call [OK]
Hint: Put ? right after the function call [OK]
Common Mistakes:
Placing ? before the function call
Using ! instead of ?
Adding ? after semicolon
3. What will be the output of this Rust code snippet?
fn divide(a: i32, b: i32) -> Result {
if b == 0 {
Err(String::from("division by zero"))
} else {
Ok(a / b)
}
}
fn main() {
match divide(10, 0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}
medium
A. Result: 0
B. Panic at runtime
C. Error: division by zero
D. No output
Solution
Step 1: Analyze the divide function call
The function is called with b = 0, triggering the error branch returning Err("division by zero").
Step 2: Check the match handling in main
The Err case prints "Error: division by zero" to the console.
Final Answer:
Error: division by zero -> Option C
Quick Check:
Error message prints on zero divisor [OK]
Hint: Check if divisor is zero to get error output [OK]
Common Mistakes:
Assuming division returns 0 instead of error
Expecting panic instead of handled error
Ignoring match arms
4. Identify the error in this Rust code snippet related to error handling:
fn read_file() -> Result {
let content = std::fs::read_to_string("file.txt");
Ok(content)
}
medium
A. File path should be a variable, not a string literal
B. Function should return String not Result
C. Using Ok instead of Err
D. Missing ? operator to propagate error
Solution
Step 1: Understand the return type and function call
The function returns Result<String, std::io::Error>, but read_to_string returns a Result itself.
Step 2: Identify missing error propagation
The code assigns content as a Result but wraps it again in Ok without handling errors. The ? operator is needed to propagate errors properly.
Final Answer:
Missing ? operator to propagate error -> Option D
Quick Check:
Use ? to handle Result errors [OK]
Hint: Use ? to unwrap or propagate Result errors [OK]
Common Mistakes:
Wrapping Result inside Ok again
Ignoring error propagation
Changing return type incorrectly
5. You want to write a function that reads two files and returns the combined content as a String. Which is the best way to handle errors using Result and the ? operator?
Choose the correct implementation:
fn read_two_files() -> Result {
// Option A
let content1 = std::fs::read_to_string("file1.txt")?;
let content2 = std::fs::read_to_string("file2.txt")?;
Ok(content1 + &content2)
// Option B
let content1 = std::fs::read_to_string("file1.txt").unwrap();
let content2 = std::fs::read_to_string("file2.txt").unwrap();
Ok(content1 + &content2)
// Option C
let content1 = std::fs::read_to_string("file1.txt").expect("file1 missing");
let content2 = std::fs::read_to_string("file2.txt").expect("file2 missing");
Ok(content1 + &content2)
// Option D
let content1 = std::fs::read_to_string("file1.txt");
let content2 = std::fs::read_to_string("file2.txt");
Ok(content1.unwrap() + &content2.unwrap())
}
hard
A. Use ? operator to propagate errors cleanly
B. Use unwrap() which panics on error
C. Use expect() which panics with message
D. Call unwrap() on Result without error handling
Solution
Step 1: Understand error propagation best practice
Using the ? operator propagates errors to the caller without panicking, making the function safe and clear.
Step 2: Compare with other options
The other options use unwrap() or expect(), which cause the program to panic on error, not recommended for robust error handling.
Final Answer:
Use ? operator to propagate errors cleanly -> Option A
Quick Check:
? propagates errors safely [OK]
Hint: Use ? to avoid panics and propagate errors [OK]
Common Mistakes:
Using unwrap or expect causing panics
Not propagating errors properly
Ignoring error handling for multiple calls
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.