TRPL: Fix Headlines, Links in "Error Handling"
- Headlines begin at 1st level now like the rest of the book - All Headlines a blank line above and below - Fix links in this chapter's TOC
This commit is contained in:
parent
d89a10b0a6
commit
39f97cfcf8
1 changed files with 39 additions and 36 deletions
|
|
@ -14,7 +14,7 @@ When done naïvely, error handling in Rust can be verbose and annoying. This
|
|||
chapter will explore those stumbling blocks and demonstrate how to use the
|
||||
standard library to make error handling concise and ergonomic.
|
||||
|
||||
## Table of Contents
|
||||
# Table of Contents
|
||||
|
||||
This chapter is very long, mostly because we start at the very beginning with
|
||||
sum types and combinators, and try to motivate the way Rust does error handling
|
||||
|
|
@ -24,11 +24,11 @@ systems may want to jump around.
|
|||
* [The Basics](#the-basics)
|
||||
* [Unwrapping explained](#unwrapping-explained)
|
||||
* [The `Option` type](#the-option-type)
|
||||
* [Composing `Option<T>` values](#composing-option-t-values)
|
||||
* [Composing `Option<T>` values](#composing-optiont-values)
|
||||
* [The `Result` type](#the-result-type)
|
||||
* [Parsing integers](#parsing-integers)
|
||||
* [The `Result` type alias idiom](#the-result-type-alias-idiom)
|
||||
* [A brief interlude: unwrapping isn't evil](#a-brief-interlude-unwrapping-isn-t-evil)
|
||||
* [A brief interlude: unwrapping isn't evil](#a-brief-interlude-unwrapping-isnt-evil)
|
||||
* [Working with multiple error types](#working-with-multiple-error-types)
|
||||
* [Composing `Option` and `Result`](#composing-option-and-result)
|
||||
* [The limits of combinators](#the-limits-of-combinators)
|
||||
|
|
@ -42,17 +42,16 @@ systems may want to jump around.
|
|||
* [Composing custom error types](#composing-custom-error-types)
|
||||
* [Advice for library writers](#advice-for-library-writers)
|
||||
* [Case study: A program to read population data](#case-study-a-program-to-read-population-data)
|
||||
* [It's on Github](#it-s-on-github)
|
||||
* [Initial setup](#initial-setup)
|
||||
* [Argument parsing](#argument-parsing)
|
||||
* [Writing the logic](#writing-the-logic)
|
||||
* [Error handling with `Box<Error>`](#error-handling-with-box-error)
|
||||
* [Error handling with `Box<Error>`](#error-handling-with-boxerror)
|
||||
* [Reading from stdin](#reading-from-stdin)
|
||||
* [Error handling with a custom type](#error-handling-with-a-custom-type)
|
||||
* [Adding functionality](#adding-functionality)
|
||||
* [The short story](#the-short-story)
|
||||
|
||||
## The Basics
|
||||
# The Basics
|
||||
|
||||
You can think of error handling as using *case analysis* to determine whether
|
||||
a computation was successful or not. As you will see, the key to ergonomic error
|
||||
|
|
@ -107,7 +106,7 @@ You can think of this style of error handling as similar to a bull running
|
|||
through a china shop. The bull will get to where it wants to go, but it will
|
||||
trample everything in the process.
|
||||
|
||||
### Unwrapping explained
|
||||
## Unwrapping explained
|
||||
|
||||
In the previous example, we claimed
|
||||
that the program would simply panic if it reached one of the two error
|
||||
|
|
@ -121,7 +120,7 @@ It would be better if we just showed the code for unwrapping because it is so
|
|||
simple, but to do that, we will first need to explore the `Option` and `Result`
|
||||
types. Both of these types have a method called `unwrap` defined on them.
|
||||
|
||||
### The `Option` type
|
||||
## The `Option` type
|
||||
|
||||
The `Option` type is
|
||||
[defined in the standard library][1]:
|
||||
|
|
@ -205,7 +204,7 @@ The `unwrap` method *abstracts away the case analysis*. This is precisely the th
|
|||
that makes `unwrap` ergonomic to use. Unfortunately, that `panic!` means that
|
||||
`unwrap` is not composable: it is the bull in the china shop.
|
||||
|
||||
#### Composing `Option<T>` values
|
||||
### Composing `Option<T>` values
|
||||
|
||||
In [`option-ex-string-find`](#code-option-ex-string-find-2)
|
||||
we saw how to use `find` to discover the extension in a file name. Of course,
|
||||
|
|
@ -382,7 +381,8 @@ Combinators make using types like `Option` ergonomic because they reduce
|
|||
explicit case analysis. They are also composable because they permit the caller
|
||||
to handle the possibility of absence in their own way. Methods like `unwrap`
|
||||
remove choices because they will panic if `Option<T>` is `None`.
|
||||
### The `Result` type
|
||||
|
||||
## The `Result` type
|
||||
|
||||
The `Result` type is also
|
||||
[defined in the standard library][6]:
|
||||
|
|
@ -442,7 +442,7 @@ way to print a human readable description of values with that type.)
|
|||
|
||||
OK, let's move on to an example.
|
||||
|
||||
#### Parsing integers
|
||||
### Parsing integers
|
||||
|
||||
The Rust standard library makes converting strings to integers dead simple.
|
||||
It's so easy in fact, that it is very tempting to write something like the
|
||||
|
|
@ -548,7 +548,9 @@ Additionally, since `Result` has a second type parameter, there are
|
|||
combinators that affect only the error type, such as
|
||||
[`map_err`](../std/result/enum.Result.html#method.map_err) (instead of
|
||||
`map`) and [`or_else`](../std/result/enum.Result.html#method.or_else)
|
||||
(instead of `and_then`). #### The `Result` type alias idiom
|
||||
(instead of `and_then`).
|
||||
|
||||
### The `Result` type alias idiom
|
||||
|
||||
In the standard library, you may frequently see types like
|
||||
`Result<i32>`. But wait, [we defined `Result`](#code-result-def-1) to
|
||||
|
|
@ -580,9 +582,7 @@ module's type alias instead of the plain definition from
|
|||
`std::result`. (This idiom is also used for
|
||||
[`fmt::Result`](../std/fmt/type.Result.html).)
|
||||
|
||||
### A brief interlude:
|
||||
|
||||
unwrapping isn't evil
|
||||
## A brief interlude: unwrapping isn't evil
|
||||
|
||||
If you've been following along, you might have noticed that I've taken a pretty
|
||||
hard line against calling methods like `unwrap` that could `panic` and abort
|
||||
|
|
@ -620,7 +620,7 @@ Now that we've covered the basics of error handling in Rust, and
|
|||
explained unwrapping, let's start exploring more of the standard
|
||||
library.
|
||||
|
||||
## Working with multiple error types
|
||||
# Working with multiple error types
|
||||
|
||||
Thus far, we've looked at error handling where everything was either an
|
||||
`Option<T>` or a `Result<T, SomeError>`. But what happens when you have both an
|
||||
|
|
@ -629,7 +629,7 @@ Thus far, we've looked at error handling where everything was either an
|
|||
challenge in front of us, and it will be the major theme throughout the rest of
|
||||
this chapter.
|
||||
|
||||
### Composing `Option` and `Result`
|
||||
## Composing `Option` and `Result`
|
||||
|
||||
So far, I've talked about combinators defined for `Option` and combinators
|
||||
defined for `Result`. We can use these combinators to compose results of
|
||||
|
|
@ -706,7 +706,7 @@ the same (because of our use of `and_then`). Since we chose to convert the
|
|||
`Option<String>` (from `argv.nth(1)`) to a `Result<String, String>`, we must
|
||||
also convert the `ParseIntError` from `arg.parse()` to a `String`.
|
||||
|
||||
### The limits of combinators
|
||||
## The limits of combinators
|
||||
|
||||
Doing IO and parsing input is a very common task, and it's one that I
|
||||
personally have done a lot of in Rust. Therefore, we will use (and continue to
|
||||
|
|
@ -839,7 +839,7 @@ With all of that said, the code is still hairy. Mastering use of combinators is
|
|||
important, but they have their limits. Let's try a different approach: early
|
||||
returns.
|
||||
|
||||
### Early returns
|
||||
## Early returns
|
||||
|
||||
I'd like to take the code from the previous section and rewrite it using *early
|
||||
returns*. Early returns let you exit the function early. We can't return early
|
||||
|
|
@ -886,7 +886,7 @@ ergonomic error handling is reducing explicit case analysis, yet we've reverted
|
|||
back to explicit case analysis here. It turns out, there are *multiple* ways to
|
||||
reduce explicit case analysis. Combinators aren't the only way.
|
||||
|
||||
### The `try!` macro
|
||||
## The `try!` macro
|
||||
|
||||
A cornerstone of error handling in Rust is the `try!` macro. The `try!` macro
|
||||
abstracts case analysis just like combinators, but unlike combinators, it also
|
||||
|
|
@ -939,7 +939,7 @@ The good news is that we will soon learn how to remove those `map_err` calls!
|
|||
The bad news is that we will need to learn a bit more about a couple important
|
||||
traits in the standard library before we can remove the `map_err` calls.
|
||||
|
||||
### Defining your own error type
|
||||
## Defining your own error type
|
||||
|
||||
Before we dive into some of the standard library error traits, I'd like to wrap
|
||||
up this section by removing the use of `String` as our error type in the
|
||||
|
|
@ -1033,14 +1033,16 @@ will do in a pinch, particularly if you're writing an application. If you're
|
|||
writing a library, defining your own error type should be strongly preferred so
|
||||
that you don't remove choices from the caller unnecessarily.
|
||||
|
||||
## Standard library traits used for error handling
|
||||
# Standard library traits used for error handling
|
||||
|
||||
The standard library defines two integral traits for error handling:
|
||||
[`std::error::Error`](../std/error/trait.Error.html) and
|
||||
[`std::convert::From`](../std/convert/trait.From.html). While `Error`
|
||||
is designed specifically for generically describing errors, the `From`
|
||||
trait serves a more general role for converting values between two
|
||||
distinct types. ### The `Error` trait
|
||||
distinct types.
|
||||
|
||||
## The `Error` trait
|
||||
|
||||
The `Error` trait is [defined in the standard
|
||||
library](../std/error/trait.Error.html):
|
||||
|
|
@ -1147,7 +1149,7 @@ We note that this is a very typical implementation of `Error`: match on your
|
|||
different error types and satisfy the contracts defined for `description` and
|
||||
`cause`.
|
||||
|
||||
### The `From` trait
|
||||
## The `From` trait
|
||||
|
||||
The `std::convert::From` trait is
|
||||
[defined in the standard
|
||||
|
|
@ -1217,7 +1219,7 @@ us a way to reliably convert errors to the same type using the same function.
|
|||
|
||||
Time to revisit an old friend; the `try!` macro.
|
||||
|
||||
### The real `try!` macro
|
||||
## The real `try!` macro
|
||||
|
||||
Previously, we presented this definition of `try!`:
|
||||
|
||||
|
|
@ -1307,7 +1309,7 @@ chapter](https://crates.io/crates/error).)
|
|||
|
||||
It's time to revisit our custom `CliError` type and tie everything together.
|
||||
|
||||
### Composing custom error types
|
||||
## Composing custom error types
|
||||
|
||||
In the last section, we looked at the real `try!` macro and how it does
|
||||
automatic type conversion for us by calling `From::from` on the error value.
|
||||
|
|
@ -1437,7 +1439,7 @@ impl From<num::ParseFloatError> for CliError {
|
|||
|
||||
And that's it!
|
||||
|
||||
### Advice for library writers
|
||||
## Advice for library writers
|
||||
|
||||
If your library needs to report custom errors, then you should
|
||||
probably define your own error type. It's up to you whether or not to
|
||||
|
|
@ -1468,7 +1470,7 @@ library defines a single error type. This is used in the standard library
|
|||
for [`io::Result`](../std/io/type.Result.html)
|
||||
and [`fmt::Result`](../std/fmt/type.Result.html).
|
||||
|
||||
## Case study: A program to read population data
|
||||
# Case study: A program to read population data
|
||||
|
||||
This chapter was long, and depending on your background, it might be
|
||||
rather dense. While there is plenty of example code to go along with
|
||||
|
|
@ -1492,7 +1494,7 @@ parse the program arguments and decode that stuff into Rust types automatically.
|
|||
[`csv`](https://crates.io/crates/csv),
|
||||
and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates.
|
||||
|
||||
### Initial setup
|
||||
## Initial setup
|
||||
|
||||
We're not going to spend a lot of time on setting up a project with
|
||||
Cargo because it is already covered well in [the Cargo
|
||||
|
|
@ -1524,7 +1526,7 @@ cargo build --release
|
|||
# Outputs: Hello, world!
|
||||
```
|
||||
|
||||
### Argument parsing
|
||||
## Argument parsing
|
||||
|
||||
Let's get argument parsing out of the way. we won't go into too much
|
||||
detail on Getopts, but there is [some good documentation][15]
|
||||
|
|
@ -1584,7 +1586,7 @@ print for the program name and template. If the user has not passed in
|
|||
the help flag, we assign the proper variables to their corresponding
|
||||
arguments.
|
||||
|
||||
### Writing the logic
|
||||
## Writing the logic
|
||||
|
||||
We're all different in how we write code, but error handling is
|
||||
usually the last thing we want to think about. This isn't very good
|
||||
|
|
@ -1681,7 +1683,7 @@ explore two different ways to approach handling these errors.
|
|||
I'd like to start with `Box<Error>`. Later, we'll see how defining our own
|
||||
error type can be useful.
|
||||
|
||||
### Error handling with `Box<Error>`
|
||||
## Error handling with `Box<Error>`
|
||||
|
||||
`Box<Error>` is nice because it *just works*. You don't need to define your own
|
||||
error types and you don't need any `From` implementations. The downside is that
|
||||
|
|
@ -1830,7 +1832,7 @@ Now that we've seen how to do proper error handling with `Box<Error>`, let's
|
|||
try a different approach with our own custom error type. But first, let's take
|
||||
a quick break from error handling and add support for reading from `stdin`.
|
||||
|
||||
### Reading from stdin
|
||||
## Reading from stdin
|
||||
|
||||
In our program, we accept a single file for input and do one pass over the
|
||||
data. This means we probably should be able to accept input on stdin. But maybe
|
||||
|
|
@ -1907,7 +1909,8 @@ fn search<P: AsRef<Path>>
|
|||
// The rest remains unchanged!
|
||||
}
|
||||
```
|
||||
### Error handling with a custom type
|
||||
|
||||
## Error handling with a custom type
|
||||
|
||||
Previously, we learned how to
|
||||
[compose errors using a custom error type](#composing-custom-error-types).
|
||||
|
|
@ -2013,7 +2016,7 @@ fn search<P: AsRef<Path>>
|
|||
|
||||
No other changes are necessary.
|
||||
|
||||
### Adding functionality
|
||||
## Adding functionality
|
||||
|
||||
Writing generic code is great, because generalizing stuff is cool, and
|
||||
it can then be useful later. But sometimes, the juice isn't worth the
|
||||
|
|
@ -2073,7 +2076,7 @@ This pretty much sums up our case study. From here, you should be ready to go
|
|||
out into the world and write your own programs and libraries with proper error
|
||||
handling.
|
||||
|
||||
## The Short Story
|
||||
# The Short Story
|
||||
|
||||
Since this chapter is long, it is useful to have a quick summary for error
|
||||
handling in Rust. These are some good “rules of thumb." They are emphatically
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue