Skip to content

TRPL: Fix Headlines, Links in "Error Handling" #28371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 12, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 39 additions & 36 deletions src/doc/trpl/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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]:
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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]:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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!`:

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down