mirror of
https://github.com/alrayyes/wiki.git
synced 2024-11-29 06:26:22 +00:00
171 lines
3.8 KiB
Markdown
171 lines
3.8 KiB
Markdown
|
---
|
|||
|
id: cbdaa6b4-cf72-45fb-ac16-79afd8900478
|
|||
|
title: Rust Recoverable Errors
|
|||
|
---
|
|||
|
|
|||
|
# match
|
|||
|
|
|||
|
In Rust we use the [match](20201006102934-pattern_syntax) expression to
|
|||
|
check for errors in the
|
|||
|
[Result](https://doc.rust-lang.org/std/result/enum.Result.html):
|
|||
|
|
|||
|
``` rust
|
|||
|
use std::fs::File;
|
|||
|
|
|||
|
fn main() {
|
|||
|
let f = File::open("hello.txt");
|
|||
|
|
|||
|
let f = match f {
|
|||
|
Ok(file) => file,
|
|||
|
Err(error) => panic!("Problem opening the file: {:?}", error),
|
|||
|
};
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
Generally speaking you want to perform different actions depending on
|
|||
|
the error type:
|
|||
|
|
|||
|
``` rust
|
|||
|
use std::fs::File;
|
|||
|
use std::io::ErrorKind;
|
|||
|
|
|||
|
fn main() {
|
|||
|
let f = File::open("hello.txt");
|
|||
|
|
|||
|
let f = match f {
|
|||
|
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),
|
|||
|
},
|
|||
|
};
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## Ditching match altogether
|
|||
|
|
|||
|
A more elegant way of writing the above:
|
|||
|
|
|||
|
``` rust
|
|||
|
use std::fs::File;
|
|||
|
use std::io::ErrorKind;
|
|||
|
|
|||
|
fn main() {
|
|||
|
let f = 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);
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
# Panic on Error shortcuts
|
|||
|
|
|||
|
## unwrap
|
|||
|
|
|||
|
If the `Result` value is `Ok`,
|
|||
|
[unwrap](https://doc.rust-lang.org/std/option/enum.Option.html#method.unwrap)
|
|||
|
will return the value inside the `Ok`. If the `Result` is of the `Err`
|
|||
|
variant, unwrap will call the `panic!` macro
|
|||
|
|
|||
|
``` rust
|
|||
|
use std::fs::File;
|
|||
|
|
|||
|
fn main() {
|
|||
|
let f = File::open("hello.txt").unwrap();
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## expect
|
|||
|
|
|||
|
[expect](https://doc.rust-lang.org/std/option/enum.Option.html#method.expect)
|
|||
|
is almost the same as unwrap, the only difference being that it allws us
|
|||
|
to choose the panic! error message:
|
|||
|
|
|||
|
``` rust
|
|||
|
use std::fs::File;
|
|||
|
|
|||
|
fn main() {
|
|||
|
let f = File::open("hello.txt").expect("Failed to open hello.txt");
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
# Propagating Errors
|
|||
|
|
|||
|
When you’re writing a function whose implementation calls something that
|
|||
|
might fail, instead of handling the error within this function, you can
|
|||
|
return the error to the calling code so that it can decide what to do.
|
|||
|
This is known as propagating the error and gives more control to the
|
|||
|
calling code, where there might be more information or logic that
|
|||
|
dictates how the error should be handled than what you have available in
|
|||
|
the context of your code.
|
|||
|
|
|||
|
``` rust
|
|||
|
#![allow(unused)]
|
|||
|
fn main() {
|
|||
|
use std::fs::File;
|
|||
|
use std::io;
|
|||
|
use std::io::Read;
|
|||
|
|
|||
|
fn read_username_from_file() -> Result<String, io::Error> {
|
|||
|
let f = File::open("hello.txt");
|
|||
|
|
|||
|
let mut f = match f {
|
|||
|
Ok(file) => file,
|
|||
|
Err(e) => return Err(e),
|
|||
|
};
|
|||
|
|
|||
|
let mut s = String::new();
|
|||
|
|
|||
|
match f.read_to_string(&mut s) {
|
|||
|
Ok(_) => Ok(s),
|
|||
|
Err(e) => Err(e),
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
This can of course be refactored to something nicer:
|
|||
|
|
|||
|
``` rust
|
|||
|
#![allow(unused)]
|
|||
|
fn main() {
|
|||
|
use std::fs::File;
|
|||
|
use std::io;
|
|||
|
use std::io::Read;
|
|||
|
|
|||
|
fn read_username_from_file() -> Result<String, io::Error> {
|
|||
|
let mut f = File::open("hello.txt")?;
|
|||
|
let mut s = String::new();
|
|||
|
f.read_to_string(&mut s)?;
|
|||
|
Ok(s)
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
And this can be refactored even more:
|
|||
|
|
|||
|
``` rust
|
|||
|
#![allow(unused)]
|
|||
|
fn main() {
|
|||
|
use std::fs::File;
|
|||
|
use std::io;
|
|||
|
use std::io::Read;
|
|||
|
|
|||
|
fn read_username_from_file() -> Result<String, io::Error> {
|
|||
|
let mut s = String::new();
|
|||
|
|
|||
|
File::open("hello.txt")?.read_to_string(&mut s)?;
|
|||
|
|
|||
|
Ok(s)
|
|||
|
}
|
|||
|
}
|
|||
|
```
|