mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-16 05:24:17 -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
|
`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 `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