Result is an enum with Ok for success and Err for errors.
Use match to handle both success and error cases clearly.
Examples
Simple example showing how to match on a Result to get the number or print an error.
Rust
use std::result::Result;
fn main() {
let result: Result<i32, &str> = Ok(10);
match result {
Ok(num) => println!("Number is {}", num),
Err(msg) => println!("Error: {}", msg),
}
}
Function returns an error if dividing by zero, otherwise returns the result.
Rust
use std::result::Result;
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Cannot divide by zero"))
} else {
Ok(a / b)
}
}
fn main() {
match divide(10, 0) {
Ok(res) => println!("Result: {}", res),
Err(e) => println!("Error: {}", e),
}
}
Example showing how to handle file opening errors using Result.
Rust
use std::fs::File;
use std::result::Result;
fn open_file() -> Result<File, std::io::Error> {
File::open("hello.txt")
}
fn main() {
match open_file() {
Ok(file) => println!("File opened successfully"),
Err(e) => println!("Failed to open file: {}", e),
}
}
Sample Program
This program tries to read a username from a file. It uses Result and the ? operator to handle errors simply. If the file is missing or unreadable, it prints an error message.
Rust
use std::fs::File;
use std::io::{self, Read};
use std::result::Result;
fn read_username_from_file() -> Result<String, io::Error> {
let mut file = File::open("username.txt")?;
let mut username = String::new();
file.read_to_string(&mut username)?;
Ok(username)
}
fn main() {
match read_username_from_file() {
Ok(name) => println!("Username: {}", name),
Err(e) => println!("Error reading username: {}", e),
}
}
OutputSuccess
Important Notes
Use the ? operator to return errors quickly and keep code clean.
Always handle both Ok and Err cases to avoid crashes.
Use meaningful error messages to help users and developers understand what went wrong.
Summary
Error handling keeps your program safe and clear.
Use Result and match to handle success and failure.
The ? operator helps write cleaner error-handling code.
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.