mirror of
https://github.com/rust-lang-cn/book-cn.git
synced 2025-02-03 07:48:41 +08:00
Add listing numbers for long or referred-to code
This commit is contained in:
parent
6e7eb0e87c
commit
211aec84b9
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user