Add listing numbers for long or referred-to code

This commit is contained in:
Carol (Nichols || Goulding) 2016-10-17 15:51:28 -04:00
parent 6e7eb0e87c
commit 211aec84b9
3 changed files with 59 additions and 22 deletions

View File

@ -92,7 +92,7 @@ Rust tell us what line in our program caused the error.
That's what the next line, the `note` is about. If we set the `RUST_BACKTRACE`
environment variable, we'll get a backtrace of exactly how the error happend.
Let's try that:
Let's try that. Listing 9-1 shows the output:
```bash
$ RUST_BACKTRACE=1 cargo run
@ -128,6 +128,11 @@ core..ops..Index<usize>>::index::hb9f10d3dadbe8101
error: Process didn't exit successfully: `target/debug/panic` (exit code: 101)
```
<caption>
Listing 9-1: The backtrace generated by a call to `panic!` displayed when
the environment variable `RUST_BACKTRACE` is set
</caption>
That's a lot of output! Line 11 of the backtrace points to the line in our
project causing the problem: `src/main.rs` line four. The key to reading the
backtrace is to start from the top and read until we see files that we wrote:

View File

@ -25,6 +25,8 @@ in more detail in Chapter XX. What you need to know for right now is that the
`T` that is what we want to return in the success case, and any type `E` that
is what we want to return in the error case.
Listing 9-2 shows an example of something that might fail: opening a file.
```rust
use std::fs::File;
@ -33,11 +35,15 @@ fn main() {
}
```
The `open` function returns a `Result`: there are many ways in which opening a
file can fail. For example, unless we created `hello.txt`, this file does not
yet exist. Before we can do anything with our `File`, we need to extract it out
of the result. Let's start with a basic tool: the `match` expression that we
learned about in Chapter 6.
<caption>
Listing 9-2: Opening a file
</caption>
The type of `f` in this example is a `Result`, because there are many ways in
which opening a file can fail. For example, unless we created `hello.txt`, this
file does not yet exist. Before we can do anything with our `File`, we need to
extract it out of the result. Listing 9-3 shows one way to handle the `Result`
with a basic tool: the `match` expression that we learned about in Chapter 6.
<!-- I'll ghost everything except the match statement lines in the libreoffice file /Carol -->
@ -55,6 +61,10 @@ error),
}
```
<caption>
Listing 9-3: Using a `match` expression to handle the `Result` variants we might have
</caption>
If we see an `Ok`, we can return the inner `file` out of the `Ok` variant. If
we see `Err`, we have to decide what to do with it. The simplest thing is to
turn our error into a `panic!` instead, by calling the macro. And since we
@ -78,7 +88,7 @@ The `Err` type `File::open` returns is [`io::Error`][ioerror]<!-- ignore -->,
which is a struct provided by the standard library. This struct has a method
`kind` that we can call to get an [`io::ErrorKind`][iokind]<!-- ignore -->
value that we can use to handle different causes of an `Err` returned from
`File::open` differently:
`File::open` differently as in Listing 9-4:
[ioerror]: ../std/io/struct.Error.html
[iokind]: ../std/io/enum.ErrorKind.html
@ -104,6 +114,10 @@ error),
}
```
<caption>
Listing 9-4: Handling different kinds of errors in different ways
</caption>
<!-- I will add ghosting and wingdings here in libreoffice /Carol -->
This example uses a *match guard* with the second arm's pattern to add a
@ -131,13 +145,13 @@ fn main() {
}
```
This has similar behavior as our previous example: If the call to `open()`
returns `Ok`, return the value inside. If it's an `Err`, panic.
This has similar behavior as the example using `match` in Listing 9-3: If the
call to `open()` returns `Ok`, return the value inside. If it's an `Err`, panic.
There's also another method, similar to `unwrap()`, but that lets us choose the
error message: `expect()`. Using `expect()` instead of `unwrap()` and providing
good error messages can convey your intent and make tracking down the source of
a panic easier. `expect()` looks like this:
There's also another method that is similar to `unwrap()`, but lets us choose
the error message: `expect()`. Using `expect()` instead of `unwrap()` and
providing good error messages can convey your intent and make tracking down the
source of a panic easier. `expect()` looks like this:
<!-- I'll ghost everything except `expect()` in the libreoffice file /Carol -->
@ -185,10 +199,10 @@ robust way instead.
### Propagating errors with `try!` or `?`
When writing a function, if you don't want to handle the error where you are,
you can return the error to the calling function. For example, here's a
function that reads a username from a file. If the file doesn't exist or can't
be read, this function will return those errors to the code that called this
function:
you can return the error to the calling function. For example, Listing 9-5
shows a function that reads a username from a file. If the file doesn't exist
or can't be read, this function will return those errors to the code that
called this function:
```rust
# use std::fs::File;
@ -212,6 +226,10 @@ fn read_username_from_file() -> Result<String, io::Error> {
}
```
<caption>
Listing 9-5: A function that returns errors to the calling code using `match`
</caption>
Since the `Result` type has two type parameters, we need to include them both
in our function signature. In this case, `File::open` and `read_to_string`
return `std::io::Error` as the value inside the `Err` variant, so we will also
@ -220,9 +238,12 @@ username as a `String` inside the `Ok` variant, so that is our success type.
This is a very common way of handling errors: propagate them upward until
you're ready to deal with them. This pattern is so common in Rust that there is
a macro for it, `try!`, and as of Rust 1.XX, dedicated syntax for it: the
question mark operator. We could have written the above like this using the
`try!` macro and it would have the same functionality as the `match` expressions:
a macro for it, `try!`, and as of Rust 1.XX <!-- We will fill this in once the
question mark is released in a stable version; we don't know for sure which
version it will be yet /Carol -->, dedicated syntax for it: the question mark
operator. We could have written the code in Listing 9-5 using the `try!` macro,
as in Listing 9-6, and it would have the same functionality as the `match`
expressions:
<!-- I'll ghost everything except the calls to `try!` in the libreoffice file
/Carol -->
@ -240,7 +261,11 @@ fn read_username_from_file() -> Result<String, io::Error> {
}
```
Or like this using the question mark operator:
<caption>
Listing 9-6: A function that returns errors to the calling code using `try!`
</caption>
Or as in Listing 9-7, which uses the question mark operator:
<!-- I'll ghost everything except the question mark operator in the libreoffice
file. Also note the `#![feature(question_mark)]` line won't be needed once this
@ -268,6 +293,9 @@ fn read_username_from_file() -> Result<String, io::Error> {
Ok(s)
}
```
<caption>
Listing 9-7: A function that returns errors to the calling code using `?`
</caption>
The `?` operator at the end of the `open` call does the same thing as the
example that uses `match` and the example that uses the `try!` macro: It will

View File

@ -106,7 +106,7 @@ and 100, and we had many functions that had this requirement, it would be
tedious (and potentially impact performance) to have a check like this in every
function. Instead, we can make a new type and put the validations in one place,
in the type's constructor. Then our functions can use the type with the
confidence that we have values that meet our requirements. Here's an example of
confidence that we have values that meet our requirements. Listing 9-8 shows
one way to define a `Guess` type that will only create an instance of `Guess`
if the `new` function gets a value between 1 and 100:
@ -131,6 +131,10 @@ impl Guess {
}
```
<caption>
Listing 9-8: A `Guess` type that will only hold values between 1 and 100
</caption>
Important to note is the `value` field of the `Guess` struct is private, so
code using this struct may not set that value directly. Callers *must* use the
`Guess::new` constructor function to create an instance of `Guess`, and they