Error propagation is a core concept in Rust that allows you to handle errors in a clean and structured way. Instead of having to handle each error manually on every step, you can easily use the ? operator to propagate errors to a higher level so that they can be handled in a single place.
In this challenge, you’ll use io::Error to represent potential issues when working with file I/O. This approach leverages Rust’s standard library for concise and idiomatic error handling.
Your Task
Your task is to implement a function that reads integers from a file, computes their sum, and gracefully propagates any errors using the ? operator.
Implement the function sum_integers_from_file:
- Takes the file path as a parameter.
- Reads the file line by line, assuming each line contains a single integer or invalid data.
- Computes and returns the sum of all integers as a
Result<i32, io::Error>. - Handles the following:
- If the file cannot be opened, propagate the
io::Error. - If a line cannot be parsed as an integer, propagate a custom
io::Errorwith a meaningful message.
- If the file cannot be opened, propagate the
Requirements
- Handle errors cleanly and propagate them using the
?operator. - For invalid lines, create an
io::Errorwithio::ErrorKind::InvalidData.
Hints
If you're stuck, here are some hints to help you solve the challenge:
<details> <summary>Click here to reveal hints</summary>- Use
std::fs::File::opento open a file. - Use
io::BufReader::newto read lines from the file. - Convert strings to integers with the
str::parsemethod. - The
io::Error::newfunction can create custom errors. - To create the error type we want for invalid numbers, you can do the following:
let error = io::Error::new(io::ErrorKind::InvalidData, "Invalid number");
- To propagate an error, use the
?operator. e.g.let file = File::open(file_path)?; - You can transform an error type to another error type by using the
map_errmethod. e.g.let num = num_str.parse::<i32>().map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Invalid number"))?;
pub fn sum_integers_from_file(file_path: &str) -> Result<i32, io::Error> {// TODO: Implement this function// Hint: Use `File::open`, `BufReader::new`, and `.lines()` to process the file.// Use `?` to propagate errors and `io::Error::new` for custom errors.}// Example usagepub fn main() {let file_path = "numbers.txt";match sum_integers_from_file(file_path) {Ok(sum) => println!("The sum is: {}", sum),Err(e) => eprintln!("Error: {}", e),}}