From fc4ae243cb8624b708aef46959437f667205f6e9 Mon Sep 17 00:00:00 2001 From: darkicewolf50 <95242911+darkicewolf50@users.noreply.github.com> Date: Wed, 22 Jan 2025 23:54:06 +0000 Subject: [PATCH] contiuning ch9.2 --- Error Handling.md | 145 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/Error Handling.md b/Error Handling.md index 54ba1f3..cb80be9 100644 --- a/Error Handling.md +++ b/Error Handling.md @@ -173,5 +173,148 @@ This return type indicates that call may succeed and reutnr a file handle that w `File::open` function needs a way to tell us whether it succeeded or failed hence the use of `Result` enum which conveys this message of failure or success When `File::open` succeeds, the value in `greeting_file_result` will be an instance of `Ok` that contains a file handle -When it fails the value in `greeting_file_result` will be an intance of `Er` that contains mroe info about the kind o error that occurred +When it fails the value in `greeting_file_result` will be an intance of `Er` that contains more info about the kind of error that occurred +We need to add a match in order to use `Result` here is one option + +```rust +use std::fs::File; + +fn main() { + let greeting_file_result = File::open("hello.txt"); + + let greeting_file = match greeting_file_result { + Ok(file) => file, + Err(error) => panic!("Problem opening the file: {error:?}"), + }; +} +``` + +This is like the `Option` enum +`Result` enum and its variants have been brought into scope by the prelude, so you dont need to specifiy `Result::` before the `Ok` and `Err` variants in the match arm + +When the result is `Ok` the code will reutrn the `file` value out itself and then we can assign that file handle to the `greeting_file`. After machh we can use the file for reading or writing. + +The other arm in `match` handles the `Err` value we get from `File::open`, in this case we choose to call the `panic!` macro with more details about the error + +### Matching on Different Errors + +You can take different actions depending on the type of failure + +For example if a file doesnt open because it doesnt exist then maybe you want you want to create the file first instead of panicing and exiting the program + +One way we can do this is by using a `match` for the returned value `Result` + +Example +```rust +use std::fs::File; +use std::io::ErrorKind; + +fn main() { + let greeting_file_result = File::open("hello.txt"); + + let greeting_file = match greeting_file_result { + Ok(file) => file, + Err(error) => match error.kind() { + ErrorKind::NotFound => match File::create("hello.txt") { + Ok(fc) => fc, + Err(e) => panic!("Problem creating the file: {e:?}"), + }, + other_error => { + panic!("Problem opening the file: {other_error:?}"); + } + }, + }; +} +``` + +The tpye that ``File::open` reutrn inside thr `Err` varian is `io:Error`, this is a struct provided by the std library + +This struct has a method `kind` which can be called to get an `io::ErrorKind` value + +The enum `io::ErrorKind` is also provided by a std library which has vairants representing the different kinds of errors that may result from an `io` operation + +The error we care about is `Error::NotFound`, this indicates that the file that we try to open doesnt exist. + +In this case we need to have a match on the outher thne use that on an inner match on `error.kind()` + +In this inner match we create a file which can also fail hence in 2nd inner match to each return a file handle or panic out of the program + +### Alternatives to Using match with `Result` + +this match expression is very useful but also primitive and boilerplate + +one example to condese this code is + +```rust +use std::fs::File; +use std::io::ErrorKind; + +fn main() { + let greeting_file = File::open("hello.txt").unwrap_or_else(|error| { + if error.kind() == ErrorKind::NotFound { + File::create("hello.txt").unwrap_or_else(|error| { + panic!("Problem creating the file: {error:?}"); + }) + } else { + panic!("Problem opening the file: {error:?}"); + } + }); +} +``` + +This accomplishes the same thing as the the example above but it uses if and else and the `unwrap_or_else` + +this is much cleaner to read even though it odesnt use and match statements + +look at the exact definition `unwrap_or_else` in the std library document + +### Shortcuts for Panic on Error: unwrap and expect + +`match` works well, but it can be a bit verbose and doesnt communicate clearly what the intent is + +`Result` has many helper methods to do specific tasks + +The `unwrap` method that is a shortcut for the `match` expression that was used before + +If the `Result` value is a `Ok` variant, `unwrap` will return the value inside the `Ok` + +If the `Result` is the `Err` variant, `unwrap` will call the `panc!` macro for us + +Here is an example of its use +```rust +use std::fs::File; + +fn main() { + let greeting_file = File::open("hello.txt").unwrap(); +} +``` + +If this code without a *hello.txt* it will panic with an error like this +``` +thread 'main' panicked at src/main.rs:4:49: +called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" } +``` + +You can also use the `expect` method lets us also choose the `panic!` error message + +This is good for providing clearer error mesages and make tracking down the source of the panic easier + +Here is an example of an `expect` in use +```rust +use std::fs::File; + +fn main() { + let greeting_file = File::open("hello.txt") + .expect("hello.txt should be included in this project"); +} +``` + +`expect` is used in the same way as `unwrap` to retunr the file handle or call the `panic!` macro + +The message is used by `expect` in its call to `panic!` as the paramter that is passed to `expect` rather than a defualt message + +`expect` is maninly used in production-quality code over `unwrap` becasue it gives more context about why the opertaion is always expected to succeed + +### Propagating Errors +When a operation fails you may want to pass back the error instead of handling the error within the function itself \ No newline at end of file