In this video, we will learn how to
handle errors gracefully as part of
Rust's emphasis on safety, you will get a
warning if you don't do something with a
result enum you receive, because the
result might be an error. We've already
seen two ways to handle errors, call
unwrap and let the program crash if it
hits an error, and using a match
expression to handle the error in a
match arm. This is one of the areas where
Rust really excels at making life better,
because when you handle errors that can
occur, you don't have to spend hours
later trying to reproduce a rare crash
just to discover that it was because you
forgot to handle an error somewhere, and
the program proceeded a good way down
the execution path before bad things
happened. Let's explore some ways to
handle errors gracefully. Let's review
the result enum. This is the definition
of result from the standard library, it
takes two generic types and wraps the
success value in okay, and the error type
in error. Rust wants you to program
safely, since result could be an error,
it's been annotated with the must use
attribute, which means the compiler will
warn you if you get a result enum and
don't do anything with it. Here's the
standard out struct, let's scroll down and
take a look at the write trait
implementation of the write all method.
This method returns a result but it
looks funny,
it only takes a unit type. Why is that?
Because this result is actually a type
def let's take a look, it passes through
the type T but it always uses this type
of error, which is the I/O library's
error. let's take a look at that. There's
three things I want to point out here.
First this error is a strut that's used
throughout the I/O library, second it has
a two string method that will give you a
message, and third it's got this error
kind enum with all of the variants for
every possible error we could care about.
Let's drill down into the error kind
enum and take a peek.
Get the variance, there's a long list of
variance for the most part we're going
to consider these variances fatal,
there is one though that we're going to
catch and ignore and that's the broken
pipe error, since we're actually going to
be dealing with pipes a lot and they
tend to break when they end, we're going
to just catch that condition and ignore
it. One nice thing about Rust is that the
main function can return result, we just
need to import result, and then return a
result from the main function. Then we
need to go to unto the end of main and
return an okay. Since we only care about
the result up here if it's an error, we
can use an if let's statement with a
pattern to match the error, then let's
return this error from main, and see how
the Rust handles it when we return an
error from main. I'm going to use the yes
utility to print an infinite number of
y's, then I'm going to pipe that to Cargo
run to have some continuous input, and
then I'm going to pipe our program's
output to head, but I'm gonna tell head
to only accept one line and then close
it standard in, which will cause us to
get a broken pipe error, and here we can
see Russ default handling, it shows error
code 32 and it formatted this nice
message for us. But wait this is such a
common thing to do that we made a syntax
just for it, replace all of that with
just a question mark, and it does exactly
the same thing, check it out.
Exactly the same behavior I'm going to
go ahead and undo this because I want to
treat the broken pipe as something
normal and not as an error. So I'm going
to check for it right here. First I need
to go up in import error kind,
then I can use error kind and grab the
variant that I want, which is the broken
pipe variant, and then if I see that then
I can break out of this, and just end
normally. Let's take a look, we'll go ahead
and run it again and we get ninety-eight
thousand three hundred and four yeses
that get through. For us a broken pipe is
normal so we ignored it and ended like
usual. Of course, we could have just
handled this all ourselves if we just
comment out the return, we can print to
standard error and choose our own
message, we can choose our own string
representation of the string, in this
case I'll just use the built-in one if
you call two string, and we can choose
our own return code and it can be whatever
we want, so if go standard process exit
I'll choose one, then to see the error
I'll need to comment out our skipping
the error, so we actually hit it, and then
when we run it we see our custom error
down here. Now that I've demonstrated
that I'd like to go back to what I had
before, because I actually liked that how
it was. Now let's go do a little bit of
cleanup, we go up here. Let's take this
buffer and put it outside the loop, so we
just create it once instead of every
time to the loop and run it one more
time to make sure we have a messed
anything up. Okay good, let's play with
the output a little bit now. I'm going to
use the carriage return to return the
cursor to the beginning of the line, and
I'm going to take this and put the
output inside the loop, so every time we
go around the loop we're gonna do some
output which is why and what the cursor
to return to the start of the line, so
that overwrites the previous value. So
let's go try it out we shouldn't see
much difference. Okay it was so fast we
didn't see any difference at all, so we
needed to do something so we can see it,
so let's go back and let's do a hundred
million, and yeah we can tell it's
definitely working going back and
rewriting itself. And that's it for this
video. In the next video, we will learn
how to handle command-line arguments
with the clap library.