Index
- Guessing Game
- Common Programming Concepts
- Understanding Ownership
- Using Structs
- Enums and Pattern Matching
- Managing Growing Projects with Packages, Crates, and Modules
- Defining Modules to Control Scope and Privacy
- Paths for Referring to an Item in the Module Tree
- Bringing Paths into Scope with the use Keyword
- Separating Modules into Different Files
- Common Collections
- Error Handling
- Generic Types, Traits, and Lifetimes
- Writing Automated Tests
- Object Oriented Programming
- Adding dependancies
- Option Take
- RefCell
- mem
- Data Structure
- Recipe
- Semi colon
- Calling rust from python
- Default
- Crytocurrency With rust
- Function chaining
- Question Mark Operator
- Tests with println
- lib and bin
- Append vector to hash map
- Random Number
- uuid4
- uwrap and option
- Blockchain with Rust
- Near Protocol
- Actix-web
Recoverable Errors with Result
TheResult
enum is defined as having two variants, Ok
and Err
, as follows:enum Result<T, E> {
Ok(T),
Err(E),
}
Ok(T),
Err(E),
}
The
T
and E
are generic type parameters: we’ll discuss generics in more detail.What you need to know right now is that
T
represents the type of the value that will be returned in a success case within the Ok
variant, and E
represents the type of the error that will be returned in a failure case within the Err
variant.Let’s call a function that returns a
Result
value because the function could fail.use std::fs::File;
fn main() {
let f = File::open("hello.txt");
}
fn main() {
let f = File::open("hello.txt");
}
How do we know
File::open
returns a Result
? We could look at the standard library API documentation, or we could ask the compiler! If we give f
a type annotation that we know is not the return type of the function and then try to compile the code, the compiler will tell us that the types don’t match. The error message will then tell us what the type of f
is. Let’s try it! We know that the return type of File::open
isn’t of type u32
, so let’s change the let f
statement to this:Error code:
use std::fs::File;
fn main() {
let f: u32 = File::open("hello.txt");
}
fn main() {
let f: u32 = File::open("hello.txt");
}
Attempting to compile now gives us the following output:
This tells us the return type of the
File::open
function is a Result<T, E>
. The generic parameter T
has been filled in here with the type of the success value, std::fs::File
, which is a file handle. The type of E
used in the error value is std::io::Error
.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),
};
}
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}
Note that, like the
Option
enum, the Result
enum and its variants have been brought into scope by the prelude, so we don’t need to specify Result::
before the Ok
and Err
variants in the match
arms.Matching on Different Errors
The code above will
panic!
no matter why File::open
failed. What we want to do instead is take different actions for different failure reasons: if File::open
failed because the file doesn’t exist, we want to create the file and return the handle to the new file. If File::open
failed for any other reason—for example, because we didn’t have permission to open the file—we still want the code to panic!
in the same way.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)
}
},
};
}
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)
}
},
};
}
Shortcuts for Panic on Error: unwrap and expect
If the
Result
value is the Ok
variant, unwrap
will return the value inside the Ok
. If the Result
is the Err
variant, unwrap
will call the panic!
macro for us. Here is an example of unwrap
in action:use std::fs::File;
fn main() {
let f = File::open("hello.txt").unwrap();
}
fn main() {
let f = File::open("hello.txt").unwrap();
}
If we run this code without a hello.txt file, we’ll see an error message from the
panic!
call that the unwrap
method makes:thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error {
repr: Os { code: 2, message: "No such file or directory" } }',
src/libcore/result.rs:906:4
repr: Os { code: 2, message: "No such file or directory" } }',
src/libcore/result.rs:906:4
Another method,
expect
, which is similar to unwrap
, lets us also choose the panic!
error message. Using expect
instead of unwrap
and providing good error messages can convey your intent and make tracking down the source of a panic easier. The syntax of expect
looks like this:use std::fs::File;
fn main() {
let f = File::open("hello.txt").expect("Failed to open hello.txt");
}
fn main() {
let f = File::open("hello.txt").expect("Failed to open hello.txt");
}
thread 'main' panicked at 'Failed to open hello.txt: Error { repr: Os { code:
2, message: "No such file or directory" } }', src/libcore/result.rs:906:4
2, message: "No such file or directory" } }', src/libcore/result.rs:906:4
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.
#![allow(unused_variables)]
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),
}
}
}