• Dc0100d6ff23e187a2999bf4f4c3e256?s=80&d=mm

    Changes from maxnuke

    maxnuke - over 3 years ago (Jan 04, 2017, 1:32 PM)
    오류 처리에서 unwrapping explained를 번역했습니다
  • Changes pending approval
      Looks like something's not quite right here.. We've been notified of the issue, and will get back to you soon.
      error-handling
      # 4.7. 오류 처리 (Error Handling) - 4%

      수많은 프로그래밍 언어들이 그렇듯, 러스트는 프로그래머가 오류를 처리할 수 있는 방법을 제공합니다. 일반적으로 말하길, 오류 처리는 크게 두가지 분류로 나뉜다고 일커집니다: 첫쩨, 예외와 변수 리턴. 둘째, 변수 리턴을 위한 러스트 OPT

      이 쳅터에서는, 러스트에서 오류들을 처리하는 포괄적인 처리 방법에 대해 다루고자합니다. 또한, 오류를 다루는 것을 한 번에 한 조각씩 소개하고자합니다. 그래야만 모든 조각들이 어떻게 딱 들어맞는지에 대한 튼튼한 기반 지식을 가질 수 있기 때문입니다.
      In this chapter, we intend to provide a comprehensive treatment of how to deal
      with errors in Rust. More than that, we will attempt to introduce error handling
      one piece at a time so that you'll come away with a solid working knowledge of
      how everything fits together.

      순진하게 하자면, 러스트의 오류 처리 방법은 수다스럽고 짜증날 수 있습니다. 이번 챕터는 우연히 마주치는 블록들을 탐험하고 정규 라이브러리를 가지고 어떻게 오류를 간결하고 인체공학적으로 다룰 수 있을지 설명하겠습니다.
      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.

      # 목차

      이번 챕터는 매우 깁니다. 대체로 우리는 sum types와 combinators들의 완전 처음부터 시작하고 있고, 러스트가 점진적으로 오류를 처리하도록 시키도록 시도하려고 하기 때문입니다. 따라서, 다른 표현적인 타입 시스템에 대한 경험이 있는 프로그래머들은 그냥 뛰어넘어버리고 싶을지도 모르겠네요.
      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
      incrementally. As such, programmers with experience in other expressive type
      systems may want to jump around.

      * [The Basics](#the-basics)
      * [Unwrapping explained](#unwrapping-explained)
      * [The `Option` type](#the-option-type)
      * [Composing `Option` 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-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)
      * [Early returns](#early-returns)
      * [The `try!` macro](#the-try-macro)
      * [Defining your own error type](#defining-your-own-error-type)
      * [Standard library traits used for error handling](#standard-library-traits-used-for-error-handling)
      * [The `Error` trait](#the-error-trait)
      * [The `From` trait](#the-from-trait)
      * [The real `try!` macro](#the-real-try-macro)
      * [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)
      * [Initial setup](#initial-setup)
      * [Argument parsing](#argument-parsing)
      * [Writing the logic](#writing-the-logic)
      * [Error handling with `Box`](#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)

      # 기본

      당신은 오류 처리를 *상태 분석*을 사용해서 연산이 성공적이었는지 아니었는지 판단하는 것이라고 생각해도 좋습니다. 앞으로 보겠지만, 인체공학적 오류 처리란 프로그래머가 계속 신경써야만 하는 명시적인 상태 분석을 줄이면서도 코드를 조립가능하게 유지하는 것을 의미합니다.
      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
      handling is reducing the amount of explicit case analysis the programmer has to
      do while keeping code composable.

      코드를 조립가능하게 유지하는 것은 중요합니다. 그렇지않으면 기대치않은 어떤 것을 만날 때마다 [`패닉`](../std/macro.panic!.html)을 사용할 수도 있습니다. (`패닉`은 현재 작업을 되돌리고, 그리고 대부분의 경우, 프로그램 전체를 강제중단시킵니다.) 아래에 예시가 있습니다.
      Keeping code composable is important, because without that requirement, we
      could [`panic`](../std/macro.panic!.html) whenever we
      come across something unexpected. (`panic` causes the current task to unwind,
      and in most cases, the entire program aborts.) Here's an example:

      ```rust,should_panic
      // 1에서 10 사이의 수 하나를 예측합니다.
      // 만일 그 수가 생각한 수가 맞으면 true를 반환하고, 그렇지 않으면 false를 반환합니다.
      // Guess a number between 1 and 10.
      // If it matches the number we had in mind, return true. Else, return false.
      fn guess(n: i32) -> bool {
      if n < 1 || n > 10 {
      panic!("Invalid number: {}", n);
      }
      n == 5
      }

      fn main() {
      guess(11);
      }
      ```

      이 코드를 실행하려고 하면, 프로그램은 강제종료되면서 다음 메시지를 출력합니다.
      If you try running this code, the program will crash with a message like this:

      ```text
      thread '
      ' panicked at 'Invalid number: 11', src/bin/panic-simple.rs:5
      ```

      또 한가지 덜 억지스러운 예를 들어보겠습니다. 정수를 매개변수로 받아서 두배로 출력하는 프로그램이 있습니다.
      Here's another example that is slightly less contrived. A program that accepts
      an integer as an argument, doubles it and prints it.

      ```rust,should_panic
      use std::env;

      fn main() {
      let mut argv = env::args();
      let arg: String = argv.nth(1).unwrap(); // error 1
      let n: i32 = arg.parse().unwrap(); // error 2
      println!("{}", 2 * n);
      }
      ```

      If you give this program zero arguments (error 1) or if the first argument
      isn't an integer (error 2), the program will panic just like in the first
      example.

      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

      In the previous example, we claimed
      that the program would simply panic if it reached one of the two error
      conditions, yet, the program does not include an explicit call to `panic` like
      the first example. This is because the
      panic is embedded in the calls to `unwrap`.

      To “unwrap” something in Rust is to say, “Give me the result of the
      computation, and if there was an error, just panic and stop the program.”
      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.

      ## `Option` 형식

      `Option` 형은
      [std 라이브러리에 정의 되어 있다][1]:
      The `Option` type is
      [defined in the standard library][1]:

      ```rust
      enum Option {
      None,
      Some(T),
      }
      ```

      `Option`형은 *부재 가능성*을 표현하기 위한 러스트 타입 시스템을 사용하는 방법중에 하나다.
      타입 시스템에 부재 가능성을 인코딩하는 것은 중요한 개념이다. 왜냐하면 컴파일러가 프로그래머가 그 부재를 처리하도록 강제 할것이기 때문이다. 문자열에서 문자를 찾기를 시도하는 예제를 보자
      The `Option` type is a way to use Rust's type system to express the
      *possibility of absence*. Encoding the possibility of absence into the type
      system is an important concept because it will cause the compiler to force the
      programmer to handle that absence. Let's take a look at an example that tries
      to find a character in a string:

      ```rust
      //'haystack'에서 유니코드 'needle'을 찾음,만약 찾았다면
      //해당 바이트의 오프셋을 반환함, 그외의 경우에는 'None'을 반환함
      // Searches `haystack` for the Unicode character `needle`. If one is found, the
      // byte offset of the character is returned. Otherwise, `None` is returned.
      fn find(haystack: &str, needle: char) -> Option {
      for (offset, c) in haystack.char_indices() {
      if c == needle {
      return Some(offset);
      }
      }
      None
      }
      ```

      알아두어야 할게,이 함수가 해당 문자를 찾을 때 `offset`을 반환하지 않는다는 거다.
      그 대신에 `Some(offset)`을 반환한다. `Some`은 변형 이자 `Option`형의 값 생성자이다.
      이것을 `fn(value: T) -> Option` 타입을 가지는 함수라고 생각할 수 있다. 이와 같은 방식으로 , `None`도 값 생성자다 인자가 없다는 것은 빼고 말이다. `None`을 `fn() -> Option`
      타입의 함수로 생각할 수 있다.
      Notice that when this function finds a matching character, it doen't just
      return the `offset`. Instead, it returns `Some(offset)`. `Some` is a variant or
      a *value constructor* for the `Option` type. You can think of it as a function
      with the type `fn(value: T) -> Option`. Correspondingly, `None` is also a
      value constructor, except it has no arguments. You can think of `None` as a
      function with the type `fn() -> Option`.

      이건 무에 대한 고뇌처럼 보인다,하지만 이건 절반에 지나지 않는다. 나머지는 반은 우리가 정의한 `find`함수를 *사용*하는 것이다. 파일의 확장자를 찾는데 써보자
      This might seem like much ado about nothing, but this is only half of the
      story. The other half is *using* the `find` function we've written. Let's try
      to use it to find the extension in a file name.

      ```rust
      # fn find(_: &str, _: char) -> Option { None }
      fn main() {
      let file_name = "foobar.rs";
      match find(file_name, '.') {
      None => println!("No file extension found."),
      Some(i) => println!("File extension: {}", &file_name[i+1..]),
      }
      }
      ```

      이 코드는 `find`함수에서 반한된 `Option`를 *경우 처리*하기 위해서 [패턴 매칭][1]을 썼다.
      사실상, 경우 처리는 `Option`내에 저장된 값을 얻기 위한 유일한 방법이다. 이 뜻은 프로그래머로써 당신은 `Option`가 `Some(t)`대신에 `None`인 경우를 처리해야 한다는 것이다
      This code uses [pattern matching][1] to do *case
      analysis* on the `Option` returned by the `find` function. In fact, case
      analysis is the only way to get at the value stored inside an `Option`. This
      means that you, as the programmer, must handle the case when an `Option` is
      `None` instead of `Some(t)`.

      잠깐만, [`unwrap-double`](#code-unwrap-double)에 있는 `unwrap`을 쓰는 게 어떨까?
      거긴 경우 처리가 없다! 그 대신에 경우 처리가 `unwrap`매서드 안에 있다. 원한다면 그것을 정의 할 수 있다
      But wait, what about `unwrap` used in [`unwrap-double`](#code-unwrap-double)?
      There was no case analysis there! Instead, the case analysis was put inside the
      `unwrap` method for you. You could define it yourself if you want:

      ```rust
      enum Option {
      None,
      Some(T),
      }

      impl Option {
      fn unwrap(self) -> T {
      match self {
      Option::Some(val) => val,
      Option::None =>
      panic!("called `Option::unwrap()` on a `None` value"),
      }
      }
      }
      ```

      `unwrap` 매서드는 *경우 처리를 추상화합니다*. 이것은 `unwrap`을 사용하기 인체 공학적으로 만듭니다. 불행하게도,`panic!`은 `unwrap`이 구성할 수 없음을 뜻한다.이건 도자기 가게 황소와 같은 격이다.
      The `unwrap` method *abstracts away the case analysis*. This is precisely the thing
      that makes `unwrap` ergonomic to use. Unfortunately, that `panic!` means that
      `unwrap` is not composable: it is the bull in the china shop.

      ### `Option` 변수들을 사용하기

      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,
      not all file names have a `.` in them, so it's possible that the file name has
      no extension. This *possibility of absence* is encoded into the types using
      `Option`. In other words, the compiler will force us to address the
      possibility that an extension does not exist. In our case, we just print out a
      message saying as such.

      Getting the extension of a file name is a pretty common operation, so it makes
      sense to put it into a function:

      ```rust
      # fn find(_: &str, _: char) -> Option { None }
      // Returns the extension of the given file name, where the extension is defined
      // as all characters proceding the first `.`.
      // If `file_name` has no `.`, then `None` is returned.
      fn extension_explicit(file_name: &str) -> Option<&str> {
      match find(file_name, '.') {
      None => None,
      Some(i) => Some(&file_name[i+1..]),
      }
      }
      ```

      (Pro-tip: don't use this code. Use the
      [`extension`](../std/path/struct.Path.html#method.extension)
      method in the standard library instead.)

      The code stays simple, but the important thing to notice is that the type of
      `find` forces us to consider the possibility of absence. This is a good thing
      because it means the compiler won't let us accidentally forget about the case
      where a file name doesn't have an extension. On the other hand, doing explicit
      case analysis like we've done in `extension_explicit` every time can get a bit
      tiresome.

      In fact, the case analysis in `extension_explicit` follows a very common
      pattern: *map* a function on to the value inside of an `Option`, unless the
      option is `None`, in which case, just return `None`.

      Rust has parametric polymorphism, so it is very easy to define a combinator
      that abstracts this pattern:

      ```rust
      fn map(option: Option, f: F) -> Option where F: FnOnce(T) -> A {
      match option {
      None => None,
      Some(value) => Some(f(value)),
      }
      }
      ```

      Indeed, `map` is [defined as a method][2] on `Option` in the standard library.

      Armed with our new combinator, we can rewrite our `extension_explicit` method
      to get rid of the case analysis:

      ```rust
      # fn find(_: &str, _: char) -> Option { None }
      // Returns the extension of the given file name, where the extension is defined
      // as all characters proceding the first `.`.
      // If `file_name` has no `.`, then `None` is returned.
      fn extension(file_name: &str) -> Option<&str> {
      find(file_name, '.').map(|i| &file_name[i+1..])
      }
      ```

      One other pattern that we find is very common is assigning a default value to
      the case when an `Option` value is `None`. For example, maybe your program
      assumes that the extension of a file is `rs` even if none is present. As you
      might imagine, the case analysis for this is not specific to file
      extensions - it can work with any `Option`:

      ```rust
      fn unwrap_or(option: Option, default: T) -> T {
      match option {
      None => default,
      Some(value) => value,
      }
      }
      ```

      The trick here is that the default value must have the same type as the value
      that might be inside the `Option`. Using it is dead simple in our case:

      ```rust
      # fn find(haystack: &str, needle: char) -> Option {
      # for (offset, c) in haystack.char_indices() {
      # if c == needle {
      # return Some(offset);
      # }
      # }
      # None
      # }
      #
      # fn extension(file_name: &str) -> Option<&str> {
      # find(file_name, '.').map(|i| &file_name[i+1..])
      # }
      fn main() {
      assert_eq!(extension("foobar.csv").unwrap_or("rs"), "csv");
      assert_eq!(extension("foobar").unwrap_or("rs"), "rs");
      }
      ```

      (Note that `unwrap_or` is [defined as a method][3] on `Option` in the
      standard library, so we use that here instead of the free-standing function we
      defined above. Don't forget to check out the more general [`unwrap_or_else`][4]
      method.)

      There is one more combinator that we think is worth paying special attention to:
      `and_then`. It makes it easy to compose distinct computations that admit the
      *possibility of absence*. For example, much of the code in this section is
      about finding an extension given a file name. In order to do this, you first
      need the file name which is typically extracted from a file *path*. While most
      file paths have a file name, not *all* of them do. For example, `.`, `..` or
      `/`.

      So, we are tasked with the challenge of finding an extension given a file
      *path*. Let's start with explicit case analysis:

      ```rust
      # fn extension(file_name: &str) -> Option<&str> { None }
      fn file_path_ext_explicit(file_path: &str) -> Option<&str> {
      match file_name(file_path) {
      None => None,
      Some(name) => match extension(name) {
      None => None,
      Some(ext) => Some(ext),
      }
      }
      }

      fn file_name(file_path: &str) -> Option<&str> {
      // implementation elided
      unimplemented!()
      }
      ```

      You might think that we could just use the `map` combinator to reduce the case
      analysis, but its type doesn't quite fit. Namely, `map` takes a function that
      does something only with the inner value. The result of that function is then
      *always* [rewrapped with `Some`](#code-option-map). Instead, we need something
      like `map`, but which allows the caller to return another `Option`. Its generic
      implementation is even simpler than `map`:

      ```rust
      fn and_then(option: Option, f: F) -> Option

      where F: FnOnce(T) -> Option
      {
      match option {
      None => None,
      Some(value) => f(value),
      }
      }
      ```

      Now we can rewrite our `file_path_ext` function without explicit case analysis:

      ```rust
      # fn extension(file_name: &str) -> Option<&str> { None }
      # fn file_name(file_path: &str) -> Option<&str> { None }
      fn file_path_ext(file_path: &str) -> Option<&str> {
      file_name(file_path).and_then(extension)
      }
      ```

      The `Option` type has many other combinators [defined in the standard
      library][5]. It is a good idea to skim this list and familiarize
      yourself with what's available—they can often reduce case analysis
      for you. Familiarizing yourself with these combinators will pay
      dividends because many of them are also defined (with similar
      semantics) for `Result`, which we will talk about next.

      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` is `None`.

      ## `Result` 형식

      The `Result` type is also
      [defined in the standard library][6]:

      ```rust
      enum Result {
      Ok(T),
      Err(E),
      }
      ```

      The `Result` type is a richer version of `Option`. Instead of expressing the
      possibility of *absence* like `Option` does, `Result` expresses the possibility
      of *error*. Usually, the *error* is used to explain why the result of some
      computation failed. This is a strictly more general form of `Option`. Consider
      the following type alias, which is semantically equivalent to the real
      `Option` in every way:

      ```rust
      type Option = Result;
      ```

      This fixes the second type parameter of `Result` to always be `()` (pronounced
      “unit” or “empty tuple”). Exactly one value inhabits the `()` type: `()`. (Yup,
      the type and value level terms have the same notation!)

      The `Result` type is a way of representing one of two possible outcomes in a
      computation. By convention, one outcome is meant to be expected or “`Ok`” while
      the other outcome is meant to be unexpected or “`Err`”.

      Just like `Option`, the `Result` type also has an
      [`unwrap` method
      defined][7]
      in the standard library. Let's define it:

      ```rust
      # enum Result { Ok(T), Err(E) }
      impl Result {
      fn unwrap(self) -> T {
      match self {
      Result::Ok(val) => val,
      Result::Err(err) =>
      panic!("called `Result::unwrap()` on an `Err` value: {:?}", err),
      }
      }
      }
      ```

      This is effectively the same as our [definition for
      `Option::unwrap`](#code-option-def-unwrap), except it includes the
      error value in the `panic!` message. This makes debugging easier, but
      it also requires us to add a [`Debug`][8] constraint on the `E` type
      parameter (which represents our error type). Since the vast majority
      of types should satisfy the `Debug` constraint, this tends to work out
      in practice. (`Debug` on a type simply means that there's a reasonable
      way to print a human readable description of values with that type.)

      OK, let's move on to an example.

      ### 변수 파싱

      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
      following:

      ```rust
      fn double_number(number_str: &str) -> i32 {
      2 * number_str.parse::().unwrap()
      }

      fn main() {
      let n: i32 = double_number("10");
      assert_eq!(n, 20);
      }
      ```

      At this point, you should be skeptical of calling `unwrap`. For example, if
      the string doesn't parse as a number, you'll get a panic:

      ```text
      thread '
      ' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', /home/rustbuild/src/rust-buildbot/slave/beta-dist-rustc-linux/build/src/libcore/result.rs:729
      ```

      This is rather unsightly, and if this happened inside a library you're
      using, you might be understandably annoyed. Instead, we should try to
      handle the error in our function and let the caller decide what to
      do. This means changing the return type of `double_number`. But to
      what? Well, that requires looking at the signature of the [`parse`
      method][9] in the standard library:

      ```rust,ignore
      impl str {
      fn parse(&self) -> Result;
      }
      ```

      Hmm. So we at least know that we need to use a `Result`. Certainly, it's
      possible that this could have returned an `Option`. After all, a string either
      parses as a number or it doesn't, right? That's certainly a reasonable way to
      go, but the implementation internally distinguishes *why* the string didn't
      parse as an integer. (Whether it's an empty string, an invalid digit, too big
      or too small.) Therefore, using a `Result` makes sense because we want to
      provide more information than simply “absence.” We want to say *why* the
      parsing failed. You should try to emulate this line of reasoning when faced
      with a choice between `Option` and `Result`. If you can provide detailed error
      information, then you probably should. (We'll see more on this later.)

      OK, but how do we write our return type? The `parse` method as defined
      above is generic over all the different number types defined in the
      standard library. We could (and probably should) also make our
      function generic, but let's favor explicitness for the moment. We only
      care about `i32`, so we need to [find its implementation of
      `FromStr`](../std/primitive.i32.html) (do a `CTRL-F` in your browser
      for “FromStr”) and look at its [associated type][10] `Err`. We did
      this so we can find the concrete error type. In this case, it's
      [`std::num::ParseIntError`](../std/num/struct.ParseIntError.html).
      Finally, we can rewrite our function:

      ```rust
      use std::num::ParseIntError;

      fn double_number(number_str: &str) -> Result {
      match number_str.parse::() {
      Ok(n) => Ok(2 * n),
      Err(err) => Err(err),
      }
      }

      fn main() {
      match double_number("10") {
      Ok(n) => assert_eq!(n, 20),
      Err(err) => println!("Error: {:?}", err),
      }
      }
      ```

      This is a little better, but now we've written a lot more code! The case
      analysis has once again bitten us.

      Combinators to the rescue! Just like `Option`, `Result` has lots of combinators
      defined as methods. There is a large intersection of common combinators between
      `Result` and `Option`. In particular, `map` is part of that intersection:

      ```rust
      use std::num::ParseIntError;

      fn double_number(number_str: &str) -> Result {
      number_str.parse::().map(|n| 2 * n)
      }

      fn main() {
      match double_number("10") {
      Ok(n) => assert_eq!(n, 20),
      Err(err) => println!("Error: {:?}", err),
      }
      }
      ```

      The usual suspects are all there for `Result`, including
      [`unwrap_or`](../std/result/enum.Result.html#method.unwrap_or) and
      [`and_then`](../std/result/enum.Result.html#method.and_then).
      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`).

      ### `Result` 형식의 다른 표현법

      In the standard library, you may frequently see types like
      `Result`. But wait, [we defined `Result`](#code-result-def-1) to
      have two type parameters. How can we get away with only specifying
      one? The key is to define a `Result` type alias that *fixes* one of
      the type parameters to a particular type. Usually the fixed type is
      the error type. For example, our previous example parsing integers
      could be rewritten like this:

      ```rust
      use std::num::ParseIntError;
      use std::result;

      type Result = result::Result;

      fn double_number(number_str: &str) -> Result {
      unimplemented!();
      }
      ```

      Why would we do this? Well, if we have a lot of functions that could return
      `ParseIntError`, then it's much more convenient to define an alias that always
      uses `ParseIntError` so that we don't have to write it out all the time.

      The most prominent place this idiom is used in the standard library is
      with [`io::Result`](../std/io/type.Result.html). Typically, one writes
      `io::Result`, which makes it clear that you're using the `io`
      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

      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
      your program. *Generally speaking*, this is good advice.

      However, `unwrap` can still be used judiciously. What exactly justifies use of
      `unwrap` is somewhat of a grey area and reasonable people can disagree. I'll
      summarize some of my *opinions* on the matter.

      * **In examples and quick 'n' dirty code.** Sometimes you're writing examples
      or a quick program, and error handling simply isn't important. Beating the
      convenience of `unwrap` can be hard in such scenarios, so it is very
      appealing.
      * **When panicking indicates a bug in the program.** When the invariants of
      your code should prevent a certain case from happening (like, say, popping
      from an empty stack), then panicking can be permissible. This is because it
      exposes a bug in your program. This can be explicit, like from an `assert!`
      failing, or it could be because your index into an array was out of bounds.

      This is probably not an exhaustive list. Moreover, when using an
      `Option`, it is often better to use its
      [`expect`](../std/option/enum.Option.html#method.expect)
      method. `expect` does exactly the same thing as `unwrap`, except it
      prints a message you give to `expect`. This makes the resulting panic
      a bit nicer to deal with, since it will show your message instead of
      “called unwrap on a `None` value.”

      My advice boils down to this: use good judgment. There's a reason why the words
      “never do X” or “Y is considered harmful” don't appear in my writing. There are
      trade offs to all things, and it is up to you as the programmer to determine
      what is acceptable for your use cases. My goal is only to help you evaluate
      trade offs as accurately as possible.

      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

      Thus far, we've looked at error handling where everything was either an
      `Option` or a `Result`. But what happens when you have both an
      `Option` and a `Result`? Or what if you have a `Result` and a
      `Result`? Handling *composition of distinct error types* is the next
      challenge in front of us, and it will be the major theme throughout the rest of
      this chapter.

      ## 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
      different computations without doing explicit case analysis.

      Of course, in real code, things aren't always as clean. Sometimes you have a
      mix of `Option` and `Result` types. Must we resort to explicit case analysis,
      or can we continue using combinators?

      For now, let's revisit one of the first examples in this chapter:

      ```rust,should_panic
      use std::env;

      fn main() {
      let mut argv = env::args();
      let arg: String = argv.nth(1).unwrap(); // error 1
      let n: i32 = arg.parse().unwrap(); // error 2
      println!("{}", 2 * n);
      }
      ```

      Given our new found knowledge of `Option`, `Result` and their various
      combinators, we should try to rewrite this so that errors are handled properly
      and the program doesn't panic if there's an error.

      The tricky aspect here is that `argv.nth(1)` produces an `Option` while
      `arg.parse()` produces a `Result`. These aren't directly composable. When faced
      with both an `Option` and a `Result`, the solution is *usually* to convert the
      `Option` to a `Result`. In our case, the absence of a command line parameter
      (from `env::args()`) means the user didn't invoke the program correctly. We
      could just use a `String` to describe the error. Let's try:

      ```rust
      use std::env;

      fn double_arg(mut argv: env::Args) -> Result {
      argv.nth(1)
      .ok_or("Please give at least one argument".to_owned())
      .and_then(|arg| arg.parse::().map_err(|err| err.to_string()))
      }

      fn main() {
      match double_arg(env::args()) {
      Ok(n) => println!("{}", n),
      Err(err) => println!("Error: {}", err),
      }
      }
      ```

      There are a couple new things in this example. The first is the use of the
      [`Option::ok_or`](../std/option/enum.Option.html#method.ok_or)
      combinator. This is one way to convert an `Option` into a `Result`. The
      conversion requires you to specify what error to use if `Option` is `None`.
      Like the other combinators we've seen, its definition is very simple:

      ```rust
      fn ok_or(option: Option, err: E) -> Result {
      match option {
      Some(val) => Ok(val),
      None => Err(err),
      }
      }
      ```

      The other new combinator used here is
      [`Result::map_err`](../std/result/enum.Result.html#method.map_err).
      This is just like `Result::map`, except it maps a function on to the *error*
      portion of a `Result` value. If the `Result` is an `Ok(...)` value, then it is
      returned unmodified.

      We use `map_err` here because it is necessary for the error types to remain
      the same (because of our use of `and_then`). Since we chose to convert the
      `Option` (from `argv.nth(1)`) to a `Result`, we must
      also convert the `ParseIntError` from `arg.parse()` to a `String`.

      ## 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
      use) IO and various parsing routines to exemplify error handling.

      Let's start simple. We are tasked with opening a file, reading all of its
      contents and converting its contents to a number. Then we multiply it by `2`
      and print the output.

      Although I've tried to convince you not to use `unwrap`, it can be useful
      to first write your code using `unwrap`. It allows you to focus on your problem
      instead of the error handling, and it exposes the points where proper error
      handling need to occur. Let's start there so we can get a handle on the code,
      and then refactor it to use better error handling.

      ```rust,should_panic
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> i32 {
      let mut file = File::open(file_path).unwrap(); // error 1
      let mut contents = String::new();
      file.read_to_string(&mut contents).unwrap(); // error 2
      let n: i32 = contents.trim().parse().unwrap(); // error 3
      2 * n
      }

      fn main() {
      let doubled = file_double("foobar");
      println!("{}", doubled);
      }
      ```

      (N.B. The `AsRef` is used because those are the
      [same bounds used on
      `std::fs::File::open`](../std/fs/struct.File.html#method.open).
      This makes it ergnomic to use any kind of string as a file path.)

      There are three different errors that can occur here:

      1. A problem opening the file.
      2. A problem reading data from the file.
      3. A problem parsing the data as a number.

      The first two problems are described via the
      [`std::io::Error`](../std/io/struct.Error.html) type. We know this
      because of the return types of
      [`std::fs::File::open`](../std/fs/struct.File.html#method.open) and
      [`std::io::Read::read_to_string`](../std/io/trait.Read.html#method.read_to_string).
      (Note that they both use the [`Result` type alias
      idiom](#the-result-type-alias-idiom) described previously. If you
      click on the `Result` type, you'll [see the type
      alias](../std/io/type.Result.html), and consequently, the underlying
      `io::Error` type.) The third problem is described by the
      [`std::num::ParseIntError`](../std/num/struct.ParseIntError.html)
      type. The `io::Error` type in particular is *pervasive* throughout the
      standard library. You will see it again and again.

      Let's start the process of refactoring the `file_double` function. To make this
      function composable with other components of the program, it should *not* panic
      if any of the above error conditions are met. Effectively, this means that the
      function should *return an error* if any of its operations fail. Our problem is
      that the return type of `file_double` is `i32`, which does not give us any
      useful way of reporting an error. Thus, we must start by changing the return
      type from `i32` to something else.

      The first thing we need to decide: should we use `Option` or `Result`? We
      certainly could use `Option` very easily. If any of the three errors occur, we
      could simply return `None`. This will work *and it is better than panicking*,
      but we can do a lot better. Instead, we should pass some detail about the error
      that occurred. Since we want to express the *possibility of error*, we should
      use `Result`. But what should `E` be? Since two *different* types of
      errors can occur, we need to convert them to a common type. One such type is
      `String`. Let's see how that impacts our code:

      ```rust
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result {
      File::open(file_path)
      .map_err(|err| err.to_string())
      .and_then(|mut file| {
      let mut contents = String::new();
      file.read_to_string(&mut contents)
      .map_err(|err| err.to_string())
      .map(|_| contents)
      })
      .and_then(|contents| {
      contents.trim().parse::()
      .map_err(|err| err.to_string())
      })
      .map(|n| 2 * n)
      }

      fn main() {
      match file_double("foobar") {
      Ok(n) => println!("{}", n),
      Err(err) => println!("Error: {}", err),
      }
      }
      ```

      This code looks a bit hairy. It can take quite a bit of practice before code
      like this becomes easy to write. The way we write it is by *following the
      types*. As soon as we changed the return type of `file_double` to
      `Result`, we had to start looking for the right combinators. In
      this case, we only used three different combinators: `and_then`, `map` and
      `map_err`.

      `and_then` is used to chain multiple computations where each computation could
      return an error. After opening the file, there are two more computations that
      could fail: reading from the file and parsing the contents as a number.
      Correspondingly, there are two calls to `and_then`.

      `map` is used to apply a function to the `Ok(...)` value of a `Result`. For
      example, the very last call to `map` multiplies the `Ok(...)` value (which is
      an `i32`) by `2`. If an error had occurred before that point, this operation
      would have been skipped because of how `map` is defined.

      `map_err` is the trick the makes all of this work. `map_err` is just like
      `map`, except it applies a function to the `Err(...)` value of a `Result`. In
      this case, we want to convert all of our errors to one type: `String`. Since
      both `io::Error` and `num::ParseIntError` implement `ToString`, we can call the
      `to_string()` method to convert them.

      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

      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
      in `file_double` from inside another closure, so we'll need to revert back to
      explicit case analysis.

      ```rust
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result {
      let mut file = match File::open(file_path) {
      Ok(file) => file,
      Err(err) => return Err(err.to_string()),
      };
      let mut contents = String::new();
      if let Err(err) = file.read_to_string(&mut contents) {
      return Err(err.to_string());
      }
      let n: i32 = match contents.trim().parse() {
      Ok(n) => n,
      Err(err) => return Err(err.to_string()),
      };
      Ok(2 * n)
      }

      fn main() {
      match file_double("foobar") {
      Ok(n) => println!("{}", n),
      Err(err) => println!("Error: {}", err),
      }
      }
      ```

      Reasonable people can disagree over whether this code is better that the code
      that uses combinators, but if you aren't familiar with the combinator approach,
      this code looks simpler to read to me. It uses explicit case analysis with
      `match` and `if let`. If an error occurs, it simply stops executing the
      function and returns the error (by converting it to a string).

      Isn't this a step backwards though? Previously, we said that the key to
      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

      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
      abstracts *control flow*. Namely, it can abstract the *early return* pattern
      seen above.

      Here is a simplified definition of a `try!` macro:

      ```rust
      macro_rules! try {
      ($e:expr) => (match $e {
      Ok(val) => val,
      Err(err) => return Err(err),
      });
      }
      ```

      (The [real definition](../std/macro.try!.html) is a bit more
      sophisticated. We will address that later.)

      Using the `try!` macro makes it very easy to simplify our last example. Since
      it does the case analysis and the early return for us, we get tighter code that
      is easier to read:

      ```rust
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result {
      let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
      let mut contents = String::new();
      try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
      let n = try!(contents.trim().parse::().map_err(|e| e.to_string()));
      Ok(2 * n)
      }

      fn main() {
      match file_double("foobar") {
      Ok(n) => println!("{}", n),
      Err(err) => println!("Error: {}", err),
      }
      }
      ```

      The `map_err` calls are still necessary given
      [our definition of `try!`](#code-try-def-simple).
      This is because the error types still need to be converted to `String`.
      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

      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
      previous examples.

      Using `String` as we did in our previous examples is convenient because it's
      easy to convert errors to strings, or even make up your own errors as strings
      on the spot. However, using `String` for your errors has some downsides.

      The first downside is that the error messages tend to clutter your
      code. It's possible to define the error messages elsewhere, but unless
      you're unusually disciplined, it is very tempting to embed the error
      message into your code. Indeed, we did exactly this in a [previous
      example](#code-error-double-string).

      The second and more important downside is that `String`s are *lossy*. That is,
      if all errors are converted to strings, then the errors we pass to the caller
      become completely opaque. The only reasonable thing the caller can do with a
      `String` error is show it to the user. Certainly, inspecting the string to
      determine the type of error is not robust. (Admittedly, this downside is far
      more important inside of a library as opposed to, say, an application.)

      For example, the `io::Error` type embeds an
      [`io::ErrorKind`](../std/io/enum.ErrorKind.html),
      which is *structured data* that represents what went wrong during an IO
      operation. This is important because you might want to react differently
      depending on the error. (e.g., A `BrokenPipe` error might mean quitting your
      program gracefully while a `NotFound` error might mean exiting with an error
      code and showing an error to the user.) With `io::ErrorKind`, the caller can
      examine the type of an error with case analysis, which is strictly superior
      to trying to tease out the details of an error inside of a `String`.

      Instead of using a `String` as an error type in our previous example of reading
      an integer from a file, we can define our own error type that represents errors
      with *structured data*. We endeavor to not drop information from underlying
      errors in case the caller wants to inspect the details.

      The ideal way to represent *one of many possibilities* is to define our own
      sum type using `enum`. In our case, an error is either an `io::Error` or a
      `num::ParseIntError`, so a natural definition arises:

      ```rust
      use std::io;
      use std::num;

      // We derive `Debug` because all types should probably derive `Debug`.
      // This gives us a reasonable human readable description of `CliError` values.
      #[derive(Debug)]
      enum CliError {
      Io(io::Error),
      Parse(num::ParseIntError),
      }
      ```

      Tweaking our code is very easy. Instead of converting errors to strings, we
      simply convert them to our `CliError` type using the corresponding value
      constructor:

      ```rust
      # #[derive(Debug)]
      # enum CliError { Io(::std::io::Error), Parse(::std::num::ParseIntError) }
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result {
      let mut file = try!(File::open(file_path).map_err(CliError::Io));
      let mut contents = String::new();
      try!(file.read_to_string(&mut contents).map_err(CliError::Io));
      let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse));
      Ok(2 * n)
      }

      fn main() {
      match file_double("foobar") {
      Ok(n) => println!("{}", n),
      Err(err) => println!("Error: {:?}", err),
      }
      }
      ```

      The only change here is switching `map_err(|e| e.to_string())` (which converts
      errors to strings) to `map_err(CliError::Io)` or `map_err(CliError::Parse)`.
      The *caller* gets to decide the level of detail to report to the user. In
      effect, using a `String` as an error type removes choices from the caller while
      using a custom `enum` error type like `CliError` gives the caller all of the
      conveniences as before in addition to *structured data* describing the error.

      A rule of thumb is to define your own error type, but a `String` error type
      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

      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

      The `Error` trait is [defined in the standard
      library](../std/error/trait.Error.html):

      ```rust
      use std::fmt::{Debug, Display};

      trait Error: Debug + Display {
      /// A short description of the error.
      fn description(&self) -> &str;

      /// The lower level cause of this error, if any.
      fn cause(&self) -> Option<&Error> { None }
      }
      ```

      This trait is super generic because it is meant to be implemented for *all*
      types that represent errors. This will prove useful for writing composable code
      as we'll see later. Otherwise, the trait allows you to do at least the
      following things:

      * Obtain a `Debug` representation of the error.
      * Obtain a user-facing `Display` representation of the error.
      * Obtain a short description of the error (via the `description` method).
      * Inspect the causal chain of an error, if one exists (via the `cause` method).

      The first two are a result of `Error` requiring impls for both `Debug` and
      `Display`. The latter two are from the two methods defined on `Error`. The
      power of `Error` comes from the fact that all error types impl `Error`, which
      means errors can be existentially quantified as a
      [trait object](../book/trait-objects.html).
      This manifests as either `Box` or `&Error`. Indeed, the `cause` method
      returns an `&Error`, which is itself a trait object. We'll revisit the
      `Error` trait's utility as a trait object later.

      For now, it suffices to show an example implementing the `Error` trait. Let's
      use the error type we defined in the
      [previous section](#defining-your-own-error-type):

      ```rust
      use std::io;
      use std::num;

      // We derive `Debug` because all types should probably derive `Debug`.
      // This gives us a reasonable human readable description of `CliError` values.
      #[derive(Debug)]
      enum CliError {
      Io(io::Error),
      Parse(num::ParseIntError),
      }
      ```

      This particular error type represents the possibility of two types of errors
      occurring: an error dealing with I/O or an error converting a string to a
      number. The error could represent as many error types as you want by adding new
      variants to the `enum` definition.

      Implementing `Error` is pretty straight-forward. It's mostly going to be a lot
      explicit case analysis.

      ```rust,ignore
      use std::error;
      use std::fmt;

      impl fmt::Display for CliError {
      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      match *self {
      // Both underlying errors already impl `Display`, so we defer to
      // their implementations.
      CliError::Io(ref err) => write!(f, "IO error: {}", err),
      CliError::Parse(ref err) => write!(f, "Parse error: {}", err),
      }
      }
      }

      impl error::Error for CliError {
      fn description(&self) -> &str {
      // Both underlying errors already impl `Error`, so we defer to their
      // implementations.
      match *self {
      CliError::Io(ref err) => err.description(),
      // Normally we can just write `err.description()`, but the error
      // type has a concrete method called `description`, which conflicts
      // with the trait method. For now, we must explicitly call
      // `description` through the `Error` trait.
      CliError::Parse(ref err) => error::Error::description(err),
      }
      }

      fn cause(&self) -> Option<&error::Error> {
      match *self {
      // N.B. Both of these implicitly cast `err` from their concrete
      // types (either `&io::Error` or `&num::ParseIntError`)
      // to a trait object `&Error`. This works because both error types
      // implement `Error`.
      CliError::Io(ref err) => Some(err),
      CliError::Parse(ref err) => Some(err),
      }
      }
      }
      ```

      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 `std::convert::From` trait is
      [defined in the standard
      library](../std/convert/trait.From.html):

      ```rust
      trait From {
      fn from(T) -> Self;
      }
      ```

      Deliciously simple, yes? `From` is very useful because it gives us a generic
      way to talk about conversion *from* a particular type `T` to some other type
      (in this case, “some other type” is the subject of the impl, or `Self`).
      The crux of `From` is the
      [set of implementations provided by the standard
      library](../std/convert/trait.From.html).

      Here are a few simple examples demonstrating how `From` works:

      ```rust
      let string: String = From::from("foo");
      let bytes: Vec = From::from("foo");
      let cow: ::std::borrow::Cow = From::from("foo");
      ```

      OK, so `From` is useful for converting between strings. But what about errors?
      It turns out, there is one critical impl:

      ```rust,ignore
      impl<'a, E: Error + 'a> From for Box
      ```

      This impl says that for *any* type that impls `Error`, we can convert it to a
      trait object `Box`. This may not seem terribly surprising, but it is
      useful in a generic context.

      Remember the two errors we were dealing with previously? Specifically,
      `io::Error` and `num::ParseIntError`. Since both impl `Error`, they work with
      `From`:

      ```rust
      use std::error::Error;
      use std::fs;
      use std::io;
      use std::num;

      // We have to jump through some hoops to actually get error values.
      let io_err: io::Error = io::Error::last_os_error();
      let parse_err: num::ParseIntError = "not a number".parse::().unwrap_err();

      // OK, here are the conversions.
      let err1: Box = From::from(io_err);
      let err2: Box = From::from(parse_err);
      ```

      There is a really important pattern to recognize here. Both `err1` and `err2`
      have the *same type*. This is because they are existentially quantified types,
      or trait objects. In particularly, their underlying type is *erased* from the
      compiler's knowledge, so it truly sees `err1` and `err2` as exactly the same.
      Additionally, we constructed `err1` and `err2` using precisely the same
      function call: `From::from`. This is because `From::from` is overloaded on both
      its argument and its return type.

      This pattern is important because it solves a problem we had earlier: it gives
      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

      Previously, we presented this definition of `try!`:

      ```rust
      macro_rules! try {
      ($e:expr) => (match $e {
      Ok(val) => val,
      Err(err) => return Err(err),
      });
      }
      ```

      This is not it's real definition. It's real definition is
      [in the standard library](../std/macro.try!.html):

      ```rust
      macro_rules! try {
      ($e:expr) => (match $e {
      Ok(val) => val,
      Err(err) => return Err(::std::convert::From::from(err)),
      });
      }
      ```

      There's one tiny but powerful change: the error value is passed through
      `From::from`. This makes the `try!` macro a lot more powerful because it gives
      you automatic type conversion for free.

      Armed with our more powerful `try!` macro, let's take a look at code we wrote
      previously to read a file and convert its contents to an integer:

      ```rust
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result {
      let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
      let mut contents = String::new();
      try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
      let n = try!(contents.trim().parse::().map_err(|e| e.to_string()));
      Ok(2 * n)
      }
      ```

      Earlier, we promised that we could get rid of the `map_err` calls. Indeed, all
      we have to do is pick a type that `From` works with. As we saw in the previous
      section, `From` has an impl that let's it convert any error type into a
      `Box`:

      ```rust
      use std::error::Error;
      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result> {
      let mut file = try!(File::open(file_path));
      let mut contents = String::new();
      try!(file.read_to_string(&mut contents));
      let n = try!(contents.trim().parse::());
      Ok(2 * n)
      }
      ```

      We are getting very close to ideal error handling. Our code has very little
      overhead as a result from error handling because the `try!` macro encapsulates
      three things simultaneously:

      1. Case analysis.
      2. Control flow.
      3. Error type conversion.

      When all three things are combined, we get code that is unencumbered by
      combinators, calls to `unwrap` or case analysis.

      There's one little nit left: the `Box` type is *opaque*. If we
      return a `Box` to the caller, the caller can't (easily) inspect
      underlying error type. The situation is certainly better than `String`
      because the caller can call methods like
      [`description`](../std/error/trait.Error.html#tymethod.description)
      and [`cause`](../std/error/trait.Error.html#method.cause), but the
      limitation remains: `Box` is opaque. (N.B. This isn't entirely
      true because Rust does have runtime reflection, which is useful in
      some scenarios that are [beyond the scope of this
      chapter](https://crates.io/crates/error).)

      It's time to revisit our custom `CliError` type and tie everything together.

      ## 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.
      In particular, we converted errors to `Box`, which works, but the type
      is opaque to callers.

      To fix this, we use the same remedy that we're already familiar with: a custom
      error type. Once again, here is the code that reads the contents of a file and
      converts it to an integer:

      ```rust
      use std::fs::File;
      use std::io::{self, Read};
      use std::num;
      use std::path::Path;

      // We derive `Debug` because all types should probably derive `Debug`.
      // This gives us a reasonable human readable description of `CliError` values.
      #[derive(Debug)]
      enum CliError {
      Io(io::Error),
      Parse(num::ParseIntError),
      }

      fn file_double_verbose>(file_path: P) -> Result {
      let mut file = try!(File::open(file_path).map_err(CliError::Io));
      let mut contents = String::new();
      try!(file.read_to_string(&mut contents).map_err(CliError::Io));
      let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse));
      Ok(2 * n)
      }
      ```

      Notice that we still have the calls to `map_err`. Why? Well, recall the
      definitions of [`try!`](#code-try-def) and [`From`](#code-from-def). The
      problem is that there is no `From` impl that allows us to convert from error
      types like `io::Error` and `num::ParseIntError` to our own custom `CliError`.
      Of course, it is easy to fix this! Since we defined `CliError`, we can impl
      `From` with it:

      ```rust
      # #[derive(Debug)]
      # enum CliError { Io(io::Error), Parse(num::ParseIntError) }
      use std::io;
      use std::num;

      impl From for CliError {
      fn from(err: io::Error) -> CliError {
      CliError::Io(err)
      }
      }

      impl From for CliError {
      fn from(err: num::ParseIntError) -> CliError {
      CliError::Parse(err)
      }
      }
      ```

      All these impls are doing is teaching `From` how to create a `CliError` from
      other error types. In our case, construction is as simple as invoking the
      corresponding value constructor. Indeed, it is *typically* this easy.

      We can finally rewrite `file_double`:

      ```rust
      # use std::io;
      # use std::num;
      # enum CliError { Io(::std::io::Error), Parse(::std::num::ParseIntError) }
      # impl From for CliError {
      # fn from(err: io::Error) -> CliError { CliError::Io(err) }
      # }
      # impl From for CliError {
      # fn from(err: num::ParseIntError) -> CliError { CliError::Parse(err) }
      # }

      use std::fs::File;
      use std::io::Read;
      use std::path::Path;

      fn file_double>(file_path: P) -> Result {
      let mut file = try!(File::open(file_path));
      let mut contents = String::new();
      try!(file.read_to_string(&mut contents));
      let n: i32 = try!(contents.trim().parse());
      Ok(2 * n)
      }
      ```

      The only thing we did here was remove the calls to `map_err`. They are no
      longer needed because the `try!` macro invokes `From::from` on the error value.
      This works because we've provided `From` impls for all the error types that
      could appear.

      If we modified our `file_double` function to perform some other operation, say,
      convert a string to a float, then we'd need to add a new variant to our error
      type:

      ```rust
      use std::io;
      use std::num;

      enum CliError {
      Io(io::Error),
      ParseInt(num::ParseIntError),
      ParseFloat(num::ParseFloatError),
      }
      ```

      And add a new `From` impl:

      ```rust
      # enum CliError {
      # Io(::std::io::Error),
      # ParseInt(num::ParseIntError),
      # ParseFloat(num::ParseFloatError),
      # }

      use std::num;

      impl From for CliError {
      fn from(err: num::ParseFloatError) -> CliError {
      CliError::ParseFloat(err)
      }
      }
      ```

      And that's it!

      ## 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
      expose its representation (like
      [`ErrorKind`](../std/io/enum.ErrorKind.html)) or keep it hidden (like
      [`ParseIntError`](../std/num/struct.ParseIntError.html)). Regardless
      of how you do it, it's usually good practice to at least provide some
      information about the error beyond just its `String`
      representation. But certainly, this will vary depending on use cases.

      At a minimum, you should probably implement the
      [`Error`](../std/error/trait.Error.html)
      trait. This will give users of your library some minimum flexibility for
      [composing errors](#the-real-try-macro). Implementing the `Error` trait also
      means that users are guaranteed the ability to obtain a string representation
      of an error (because it requires impls for both `fmt::Debug` and
      `fmt::Display`).

      Beyond that, it can also be useful to provide implementations of `From` on your
      error types. This allows you (the library author) and your users to
      [compose more detailed errors](#composing-custom-error-types). For example,
      [`csv::Error`](http://burntsushi.net/rustdoc/csv/enum.Error.html)
      provides `From` impls for both `io::Error` and `byteorder::Error`.

      Finally, depending on your tastes, you may also want to define a
      [`Result` type alias](#the-result-type-alias-idiom), particularly if your
      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

      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
      the prose, most of it was specifically designed to be pedagogical. So,
      we're going to do something new: a case study.

      For this, we're going to build up a command line program that lets you
      query world population data. The objective is simple: you give it a location
      and it will tell you the population. Despite the simplicity, there is a lot
      that can go wrong!

      The data we'll be using comes from the [Data Science
      Toolkit][11]. I've prepared some data from it for this exercise. You
      can either grab the [world population data][12] (41MB gzip compressed,
      145MB uncompressed) or just the [US population data][13] (2.2MB gzip
      compressed, 7.2MB uncompressed).

      Up until now, we've kept the code limited to Rust's standard library. For a real
      task like this though, we'll want to at least use something to parse CSV data,
      parse the program arguments and decode that stuff into Rust types automatically. For that, we'll use the
      [`csv`](https://crates.io/crates/csv),
      and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates.

      ## 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
      chapter](../book/hello-cargo) and [Cargo's documentation][14].

      To get started from scratch, run `cargo new --bin city-pop` and make sure your
      `Cargo.toml` looks something like this:

      ```text
      [package]
      name = "city-pop"
      version = "0.1.0"
      authors = ["Andrew Gallant "]

      [[bin]]
      name = "city-pop"

      [dependencies]
      csv = "0.*"
      rustc-serialize = "0.*"
      getopts = "0.*"
      ```

      You should already be able to run:

      ```text
      cargo build --release
      ./target/release/city-pop
      # Outputs: Hello, world!
      ```

      ## 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]
      describing it. The short story is that Getopts generates an argument
      parser and a help message from a vector of options (The fact that it
      is a vector is hidden behind a struct and a set of methods). Once the
      parsing is done, we can decode the program arguments into a Rust
      struct. From there, we can get information about the flags, for
      instance, wether they were passed in, and what arguments they
      had. Here's our program with the appropriate `extern crate`
      statements, and the basic argument setup for Getopts:

      ```rust,ignore
      extern crate getopts;
      extern crate rustc_serialize;

      use getopts::Options;
      use std::env;

      fn print_usage(program: &str, opts: Options) {
      println!("{}", opts.usage(&format!("Usage: {} [options] ", program)));
      }

      fn main() {
      let args: Vec = env::args().collect();
      let program = args[0].clone();

      let mut opts = Options::new();
      opts.optflag("h", "help", "Show this usage message.");

      let matches = match opts.parse(&args[1..]) {
      Ok(m) => { m }
      Err(e) => { panic!(e.to_string()) }
      };
      if matches.opt_present("h") {
      print_usage(&program, opts);
      return;
      }
      let data_path = args[1].clone();
      let city = args[2].clone();

      // Do stuff with information
      }
      ```

      First, we get a vector of the arguments passed into our program. We
      then store the first one, knowing that it is our program's name. Once
      that's done, we set up our argument flags, in this case a simplistic
      help message flag. Once we have the argument flags set up, we use
      `Options.parse` to parse the argument vector (starting from index one,
      becouse index 0 is the program name). If this was successful, we
      assign matches to the parsed object, if not, we panic. Once past that,
      we test if the user passed in the help flag, and if so print the usage
      message. The option help messages are constructed by Getopts, so all
      we have to do to print the usage message is tell it what we want it to
      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

      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
      practice for good design, but it can be useful for rapidly
      prototyping. In our case, because Rust forces us to be explicit about
      error handling, it will also make it obvious what parts of our program
      can cause errors. Why? Because Rust will make us call `unwrap`! This
      can give us a nice bird's eye view of how we need to approach error
      handling.

      In this case study, the logic is really simple. All we need to do is parse the
      CSV data given to us and print out a field in matching rows. Let's do it. (Make
      sure to add `extern crate csv;` to the top of your file.)

      ```rust,ignore
      // This struct represents the data in each row of the CSV file.
      // Type based decoding absolves us of a lot of the nitty gritty error
      // handling, like parsing strings as integers or floats.
      #[derive(Debug, RustcDecodable)]
      struct Row {
      country: String,
      city: String,
      accent_city: String,
      region: String,

      // Not every row has data for the population, latitude or longitude!
      // So we express them as `Option` types, which admits the possibility of
      // absence. The CSV parser will fill in the correct value for us.
      population: Option,
      latitude: Option,
      longitude: Option,
      }

      fn print_usage(program: &str, opts: Options) {
      println!("{}", opts.usage(&format!("Usage: {} [options] ", program)));
      }

      fn main() {
      let args: Vec = env::args().collect();
      let program = args[0].clone();

      let mut opts = Options::new();
      opts.optflag("h", "help", "Show this usage message.");

      let matches = match opts.parse(&args[1..]) {
      Ok(m) => { m }
      Err(e) => { panic!(e.to_string()) }
      };

      if matches.opt_present("h") {
      print_usage(&program, opts);
      return;
      }

      let data_file = args[1].clone();
      let data_path = Path::new(&data_file);
      let city = args[2].clone();

      let file = fs::File::open(data_path).unwrap();
      let mut rdr = csv::Reader::from_reader(file);

      for row in rdr.decode::() {
      let row = row.unwrap();

      if row.city == city {
      println!("{}, {}: {:?}",
      row.city, row.country,
      row.population.expect("population count"));
      }
      }
      }
      ```

      Let's outline the errors. We can start with the obvious: the three places that
      `unwrap` is called:

      1. [`fs::File::open`](../std/fs/struct.File.html#method.open)
      can return an
      [`io::Error`](../std/io/struct.Error.html).
      2. [`csv::Reader::decode`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.decode)
      decodes one record at a time, and
      [decoding a
      record](http://burntsushi.net/rustdoc/csv/struct.DecodedRecords.html)
      (look at the `Item` associated type on the `Iterator` impl)
      can produce a
      [`csv::Error`](http://burntsushi.net/rustdoc/csv/enum.Error.html).
      3. If `row.population` is `None`, then calling `expect` will panic.

      Are there any others? What if we can't find a matching city? Tools like `grep`
      will return an error code, so we probably should too. So we have logic errors
      specific to our problem, IO errors and CSV parsing errors. We're going to
      explore two different ways to approach handling these errors.

      I'd like to start with `Box`. Later, we'll see how defining our own
      error type can be useful.

      ## Error handling with `Box`

      `Box` 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
      since `Box` is a trait object, it *erases the type*, which means the
      compiler can no longer reason about its underlying type.

      [Previously](#the-limits-of-combinators) we started refactoring our code by
      changing the type of our function from `T` to `Result`. In
      this case, `OurErrorType` is just `Box`. But what's `T`? And can we add
      a return type to `main`?

      The answer to the second question is no, we can't. That means we'll need to
      write a new function. But what is `T`? The simplest thing we can do is to
      return a list of matching `Row` values as a `Vec`. (Better code would
      return an iterator, but that is left as an exercise to the reader.)

      Let's refactor our code into its own function, but keep the calls to `unwrap`.
      Note that we opt to handle the possibility of a missing population count by
      simply ignoring that row.

      ```rust,ignore
      struct Row {
      // unchanged
      }

      struct PopulationCount {
      city: String,
      country: String,
      // This is no longer an `Option` because values of this type are only
      // constructed if they have a population count.
      count: u64,
      }

      fn print_usage(program: &str, opts: Options) {
      println!("{}", opts.usage(&format!("Usage: {} [options] ", program)));
      }

      fn search>(file_path: P, city: &str) -> Vec {
      let mut found = vec![];
      let file = fs::File::open(file_path).unwrap();
      let mut rdr = csv::Reader::from_reader(file);
      for row in rdr.decode::() {
      let row = row.unwrap();
      match row.population {
      None => { } // skip it
      Some(count) => if row.city == city {
      found.push(PopulationCount {
      city: row.city,
      country: row.country,
      count: count,
      });
      },
      }
      }
      found
      }

      fn main() {
      let args: Vec = env::args().collect();
      let program = args[0].clone();

      let mut opts = Options::new();
      opts.optflag("h", "help", "Show this usage message.");

      let matches = match opts.parse(&args[1..]) {
      Ok(m) => { m }
      Err(e) => { panic!(e.to_string()) }
      };
      if matches.opt_present("h") {
      print_usage(&program, opts);
      return;
      }

      let data_file = args[1].clone();
      let data_path = Path::new(&data_file);
      let city = args[2].clone();
      for pop in search(&data_path, &city) {
      println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
      }
      }

      ```

      While we got rid of one use of `expect` (which is a nicer variant of `unwrap`),
      we still should handle the absence of any search results.

      To convert this to proper error handling, we need to do the following:

      1. Change the return type of `search` to be `Result,
      Box>`.
      2. Use the [`try!` macro](#code-try-def) so that errors are returned to the
      caller instead of panicking the program.
      3. Handle the error in `main`.

      Let's try it:

      ```rust,ignore
      fn search>
      (file_path: P, city: &str)
      -> Result, Box> {
      let mut found = vec![];
      let file = try!(fs::File::open(file_path));
      let mut rdr = csv::Reader::from_reader(file);
      for row in rdr.decode::() {
      let row = try!(row);
      match row.population {
      None => { } // skip it
      Some(count) => if row.city == city {
      found.push(PopulationCount {
      city: row.city,
      country: row.country,
      count: count,
      });
      },
      }
      }
      if found.is_empty() {
      Err(From::from("No matching cities with a population were found."))
      } else {
      Ok(found)
      }
      }
      ```

      Instead of `x.unwrap()`, we now have `try!(x)`. Since our function returns a
      `Result`, the `try!` macro will return early from the function if an
      error occurs.

      There is one big gotcha in this code: we used `Box`
      instead of `Box`. We did this so we could convert a plain string to an
      error type. We need these extra bounds so that we can use the
      [corresponding `From`
      impls](../std/convert/trait.From.html):

      ```rust,ignore
      // We are making use of this impl in the code above, since we call `From::from`
      // on a `&'static str`.
      impl<'a, 'b> From<&'b str> for Box

      // But this is also useful when you need to allocate a new string for an
      // error message, usually with `format!`.
      impl From for Box
      ```

      Now that we've seen how to do proper error handling with `Box`, 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

      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
      we like the current format too—so let's have both!

      Adding support for stdin is actually quite easy. There are only two things we
      have to do:

      1. Tweak the program arguments so that a single parameter—the
      city—can be accepted while the population data is read from stdin.
      2. Modify the program so that an option `-f` can take the file, if it
      is not passed into stdin.
      3. Modify the `search` function to take an *optional* file path. When `None`,
      it should know to read from stdin.

      First, here's the new usage:

      ```rust,ignore
      fn print_usage(program: &str, opts: Options) {
      println!("{}", opts.usage(&format!("Usage: {} [options] ", program)));
      }
      ```
      The next part is going to be only a little harder:

      ```rust,ignore
      ...
      let mut opts = Options::new();
      opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
      opts.optflag("h", "help", "Show this usage message.");
      ...
      let file = matches.opt_str("f");
      let data_file = file.as_ref().map(Path::new);

      let city = if !matches.free.is_empty() {
      matches.free[0].clone()
      } else {
      print_usage(&program, opts);
      return;
      };

      for pop in search(&data_file, &city) {
      println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
      }
      ...
      ```

      In this peice of code, we take `file` (which has the type
      `Option`), and convert it to a type that `search` can use, in
      this case, `&Option>`. Do do this, we take a reference of
      file, and map `Path::new` onto it. In this case, `as_ref()` converts
      the `Option` into an `Option<&str>`, and from there, we can
      execute `Path::new` to the content of the optional, and return the
      optional of the new value. Once we have that, it is a simple matter of
      getting the `city` argument and executing `search`.

      Modifying `search` is slightly trickier. The `csv` crate can build a
      parser out of
      [any type that implements `io::Read`](http://burntsushi.net/rustdoc/csv/struct.Reader.html#method.from_reader).
      But how can we use the same code over both types? There's actually a
      couple ways we could go about this. One way is to write `search` such
      that it is generic on some type parameter `R` that satisfies
      `io::Read`. Another way is to just use trait objects:

      ```rust,ignore
      fn search>
      (file_path: &Option

      , city: &str)
      -> Result, Box> {
      let mut found = vec![];
      let input: Box = match *file_path {
      None => Box::new(io::stdin()),
      Some(ref file_path) => Box::new(try!(fs::File::open(file_path))),
      };
      let mut rdr = csv::Reader::from_reader(input);
      // The rest remains unchanged!
      }
      ```

      ## Error handling with a custom type

      Previously, we learned how to
      [compose errors using a custom error type](#composing-custom-error-types).
      We did this by defining our error type as an `enum` and implementing `Error`
      and `From`.

      Since we have three distinct errors (IO, CSV parsing and not found), let's
      define an `enum` with three variants:

      ```rust,ignore
      #[derive(Debug)]
      enum CliError {
      Io(io::Error),
      Csv(csv::Error),
      NotFound,
      }
      ```

      And now for impls on `Display` and `Error`:

      ```rust,ignore
      impl fmt::Display for CliError {
      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      match *self {
      CliError::Io(ref err) => err.fmt(f),
      CliError::Csv(ref err) => err.fmt(f),
      CliError::NotFound => write!(f, "No matching cities with a \
      population were found."),
      }
      }
      }

      impl Error for CliError {
      fn description(&self) -> &str {
      match *self {
      CliError::Io(ref err) => err.description(),
      CliError::Csv(ref err) => err.description(),
      CliError::NotFound => "not found",
      }
      }
      }
      ```

      Before we can use our `CliError` type in our `search` function, we need to
      provide a couple `From` impls. How do we know which impls to provide? Well,
      we'll need to convert from both `io::Error` and `csv::Error` to `CliError`.
      Those are the only external errors, so we'll only need two `From` impls for
      now:

      ```rust,ignore
      impl From for CliError {
      fn from(err: io::Error) -> CliError {
      CliError::Io(err)
      }
      }

      impl From for CliError {
      fn from(err: csv::Error) -> CliError {
      CliError::Csv(err)
      }
      }
      ```

      The `From` impls are important because of how
      [`try!` is defined](#code-try-def). In particular, if an error occurs,
      `From::from` is called on the error, which in this case, will convert it to our
      own error type `CliError`.

      With the `From` impls done, we only need to make two small tweaks to our
      `search` function: the return type and the “not found” error. Here it is in
      full:

      ```rust,ignore
      fn search>
      (file_path: &Option

      , city: &str)
      -> Result, CliError> {
      let mut found = vec![];
      let input: Box = match *file_path {
      None => Box::new(io::stdin()),
      Some(ref file_path) => Box::new(try!(fs::File::open(file_path))),
      };
      let mut rdr = csv::Reader::from_reader(input);
      for row in rdr.decode::() {
      let row = try!(row);
      match row.population {
      None => { } // skip it
      Some(count) => if row.city == city {
      found.push(PopulationCount {
      city: row.city,
      country: row.country,
      count: count,
      });
      },
      }
      }
      if found.is_empty() {
      Err(CliError::NotFound)
      } else {
      Ok(found)
      }
      }
      ```

      No other changes are necessary.

      ## 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
      squeeze. Look at what we just did in the previous step:

      1. Defined a new error type.
      2. Added impls for `Error`, `Display` and two for `From`.

      The big downside here is that our program didn't improve a whole lot.
      There is quite a bit of overhead to representing errors with `enum`s,
      especially in short programs like this.

      *One* useful aspect of using a custom error type like we've done here is that
      the `main` function can now choose to handle errors differently. Previously,
      with `Box`, it didn't have much of a choice: just print the message.
      We're still doing that here, but what if we wanted to, say, add a `--quiet`
      flag? The `--quiet` flag should silence any verbose output.

      Right now, if the program doesn't find a match, it will output a message saying
      so. This can be a little clumsy, especially if you intend for the program to
      be used in shell scripts.

      So let's start by adding the flags. Like before, we need to tweak the usage
      string and add a flag to the Option variable. Once were done that, Getopts does the rest:

      ```rust,ignore
      ...
      let mut opts = Options::new();
      opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
      opts.optflag("h", "help", "Show this usage message.");
      opts.optflag("q", "quit", "Silences errors and warnings.");
      ...
      ```

      Now we just need to implement our “quiet” functionality. This requires us to
      tweak the case analysis in `main`:

      ```rust,ignore
      match search(&args.arg_data_path, &args.arg_city) {
      Err(CliError::NotFound) if args.flag_quiet => process::exit(1),
      Err(err) => fatal!("{}", err),
      Ok(pops) => for pop in pops {
      println!("{}, {}: {:?}", pop.city, pop.country, pop.count);
      }
      }
      ```

      Certainly, we don't want to be quiet if there was an IO error or if the data
      failed to parse. Therefore, we use case analysis to check if the error type is
      `NotFound` *and* if `--quiet` has been enabled. If the search failed, we still
      quit with an exit code (following `grep`'s convention).

      If we had stuck with `Box`, then it would be pretty tricky to implement
      the `--quiet` functionality.

      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

      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
      *not* commandments. There are probably good reasons to break every one of these
      heuristics!

      * If you're writing short example code that would be overburdened by error
      handling, it's probably just fine to use `unwrap` (whether that's
      [`Result::unwrap`](../std/result/enum.Result.html#method.unwrap),
      [`Option::unwrap`](../std/option/enum.Option.html#method.unwrap)
      or preferably
      [`Option::expect`](../std/option/enum.Option.html#method.expect)).
      Consumers of your code should know to use proper error handling. (If they
      don't, send them here!)
      * If you're writing a quick 'n' dirty program, don't feel ashamed if you use
      `unwrap`. Be warned: if it winds up in someone else's hands, don't be
      surprised if they are agitated by poor error messages!
      * If you're writing a quick 'n' dirty program and feel ashamed about panicking
      anyway, then using either a `String` or a `Box` for your
      error type (the `Box` type is because of the
      [available `From` impls](../std/convert/trait.From.html)).
      * Otherwise, in a program, define your own error types with appropriate
      [`From`](../std/convert/trait.From.html)
      and
      [`Error`](../std/error/trait.Error.html)
      impls to make the [`try!`](../std/macro.try!.html)
      macro more ergnomic.
      * If you're writing a library and your code can produce errors, define your own
      error type and implement the
      [`std::error::Error`](../std/error/trait.Error.html)
      trait. Where appropriate, implement
      [`From`](../std/convert/trait.From.html) to make both
      your library code and the caller's code easier to write. (Because of Rust's
      coherence rules, callers will not be able to impl `From` on your error type,
      so your library should do it.)
      * Learn the combinators defined on
      [`Option`](../std/option/enum.Option.html)
      and
      [`Result`](../std/result/enum.Result.html).
      Using them exclusively can be a bit tiring at times, but I've personally
      found a healthy mix of `try!` and combinators to be quite appealing.
      `and_then`, `map` and `unwrap_or` are my favorites.

      [1]: ../book/patterns.html
      [2]: ../std/option/enum.Option.html#method.map
      [3]: ../std/option/enum.Option.html#method.unwrap_or
      [4]: ../std/option/enum.Option.html#method.unwrap_or_else
      [5]: ../std/option/enum.Option.html
      [6]: ../std/result/
      [7]: ../std/result/enum.Result.html#method.unwrap
      [8]: ../std/fmt/trait.Debug.html
      [9]: ../std/primitive.str.html#method.parse
      [10]: ../book/associated-types.html
      [11]: https://github.com/petewarden/dstkdata
      [12]: http://burntsushi.net/stuff/worldcitiespop.csv.gz
      [13]: http://burntsushi.net/stuff/uscitiespop.csv.gz
      [14]: http://doc.crates.io/guide.html
      [15]: http://doc.rust-lang.org/getopts/getopts/index.html