mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-15 13:04:18 -06:00
contiuning ch9.2
This commit is contained in:
parent
a6eeda7f49
commit
fc4ae243cb
@ -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<T, E>`
|
||||
|
||||
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<T, E>`
|
||||
|
||||
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<T, E>` 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
|
Loading…
x
Reference in New Issue
Block a user