Skip to content

Commit

Permalink
Link to chapters mentioned in chapter 12
Browse files Browse the repository at this point in the history
Fixes #1887.
  • Loading branch information
carols10cents committed Apr 16, 2019
1 parent 6678e82 commit db919bc
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 63 deletions.
23 changes: 17 additions & 6 deletions src/ch12-00-an-io-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,22 @@ the background knowledge you need to understand a real-world project such as

Our `grep` project will combine a number of concepts you’ve learned so far:

* Organizing code (using what you learned about modules in Chapter 7)
* Using vectors and strings (collections, Chapter 8)
* Handling errors (Chapter 9)
* Using traits and lifetimes where appropriate (Chapter 10)
* Writing tests (Chapter 11)
* Organizing code (using what you learned about modules in [Chapter 7][ch7]<!--
ignore -->)
* Using vectors and strings (collections, [Chapter 8][ch8]<!-- ignore -->)
* Handling errors ([Chapter 9][ch9]<!-- ignore -->)
* Using traits and lifetimes where appropriate ([Chapter 10][ch10]<!-- ignore
-->)
* Writing tests ([Chapter 11][ch11]<!-- ignore -->)

We’ll also briefly introduce closures, iterators, and trait objects, which
Chapters 13 and 17 will cover in detail.
Chapters [13][ch13]<!-- ignore --> and [17][ch17]<!-- ignore --> will cover in
detail.

[ch7]: ch07-00-managing-growing-projects-with-packages-crates-and-modules.html
[ch8]: ch08-00-common-collections.html
[ch9]: ch09-00-error-handling.html
[ch10]: ch10-00-generics.html
[ch11]: ch11-00-testing.html
[ch13]: ch13-00-functional-features.html
[ch17]: ch17-00-oop.html
27 changes: 15 additions & 12 deletions src/ch12-01-accepting-command-line-arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ just learning this concept, let’s implement this capability ourselves.
To enable `minigrep` to read the values of command line arguments we pass to
it, we’ll need a function provided in Rust’s standard library, which is
`std::env::args`. This function returns an iterator of the command line
arguments that were given to `minigrep`. We’ll cover iterators fully in Chapter 13.
For now, you only need to know two details about iterators: iterators
produce a series of values, and we can call the `collect` method on an iterator
to turn it into a collection, such as a vector, containing all the elements the
iterator produces.
arguments that were given to `minigrep`. We’ll cover iterators fully in
[Chapter 13][ch13]<!-- ignore -->. For now, you only need to know two details
about iterators: iterators produce a series of values, and we can call the
`collect` method on an iterator to turn it into a collection, such as a vector,
containing all the elements the iterator produces.

Use the code in Listing 12-1 to allow your `minigrep` program to read any
command line arguments passed to it and then collect the values into a vector.
Expand All @@ -54,13 +54,13 @@ a vector and printing them</span>

First, we bring the `std::env` module into scope with a `use` statement so we
can use its `args` function. Notice that the `std::env::args` function is
nested in two levels of modules. As we discussed in Chapter 7, in cases where
the desired function is nested in more than one module, it’s conventional to
bring the parent module into scope rather than the function. By doing so, we
can easily use other functions from `std::env`. It’s also less ambiguous than
adding `use std::env::args` and then calling the function with just `args`,
because `args` might easily be mistaken for a function that’s defined in the
current module.
nested in two levels of modules. As we discussed in [Chapter
7][ch7-idiomatic-use]<!-- ignore -->, in cases where the desired function is
nested in more than one module, it’s conventional to bring the parent module
into scope rather than the function. By doing so, we can easily use other
functions from `std::env`. It’s also less ambiguous than adding `use
std::env::args` and then calling the function with just `args`, because `args`
might easily be mistaken for a function that’s defined in the current module.

> ### The `args` Function and Invalid Unicode
>
Expand Down Expand Up @@ -151,3 +151,6 @@ saved into the right variables. Later we’ll add some error handling to deal
with certain potential erroneous situations, such as when the user provides no
arguments; for now, we’ll ignore that situation and work on adding file-reading
capabilities instead.

[ch13]: ch13-00-functional-features.html
[ch7-idiomatic-use]: ch07-04-bringing-paths-into-scope-with-the-use-keyword.html#creating-idiomatic-use-paths
72 changes: 40 additions & 32 deletions src/ch12-03-improving-error-handling-and-modularity.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,14 @@ trade-off.
> ### The Trade-Offs of Using `clone`
>
> There’s a tendency among many Rustaceans to avoid using `clone` to fix
> ownership problems because of its runtime cost. In Chapter 13, you’ll learn
> how to use more efficient methods in this type of situation. But for now,
> it’s okay to copy a few strings to continue making progress because you’ll
> make these copies only once and your filename and query string are very
> small. It’s better to have a working program that’s a bit inefficient than to
> try to hyperoptimize code on your first pass. As you become more experienced
> with Rust, it’ll be easier to start with the most efficient solution, but for
> now, it’s perfectly acceptable to call `clone`.
> ownership problems because of its runtime cost. In [Chapter 13][ch13]<!--
> ignore -->, you’ll learn how to use more efficient methods in this type of
> situation. But for now, it’s okay to copy a few strings to continue making
> progress because you’ll make these copies only once and your filename and
> query string are very small. It’s better to have a working program that’s a
> bit inefficient than to try to hyperoptimize code on your first pass. As you
> become more experienced with Rust, it’ll be easier to start with the most
> efficient solution, but for now, it’s perfectly acceptable to call `clone`.
We’ve updated `main` so it places the instance of `Config` returned by
`parse_config` into a variable named `config`, and we updated the code that
Expand Down Expand Up @@ -304,13 +304,13 @@ fn new(args: &[String]) -> Config {
<span class="caption">Listing 12-8: Adding a check for the number of
arguments</span>

This code is similar to the `Guess::new` function we wrote in Listing 9-10,
where we called `panic!` when the `value` argument was out of the range of
valid values. Instead of checking for a range of values here, we’re checking
that the length of `args` is at least 3 and the rest of the function can
operate under the assumption that this condition has been met. If `args` has
fewer than three items, this condition will be true, and we call the `panic!`
macro to end the program immediately.
This code is similar to [the `Guess::new` function we wrote in Listing
9-10][ch9-custom-types]<!-- ignore -->, where we called `panic!` when the
`value` argument was out of the range of valid values. Instead of checking for
a range of values here, we’re checking that the length of `args` is at least 3
and the rest of the function can operate under the assumption that this
condition has been met. If `args` has fewer than three items, this condition
will be true, and we call the `panic!` macro to end the program immediately.

With these extra few lines of code in `new`, let’s run the program without any
arguments again to see what the error looks like now:
Expand All @@ -327,10 +327,10 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace.
This output is better: we now have a reasonable error message. However, we also
have extraneous information we don’t want to give to our users. Perhaps using
the technique we used in Listing 9-10 isn’t the best to use here: a call to
`panic!` is more appropriate for a programming problem than a usage problem, as
discussed in Chapter 9. Instead, we can use the other technique you learned
about in Chapter 9—returning a `Result` that indicates either success or an
error.
`panic!` is more appropriate for a programming problem than a usage problem,
[as discussed in Chapter 9][ch9-error-guidelines]<!-- ignore -->. Instead, we
can use the other technique you learned about in Chapter 9—[returning a
`Result`][ch9-result]<!-- ignore --> that indicates either success or an error.

#### Returning a `Result` from `new` Instead of Calling `panic!`

Expand Down Expand Up @@ -416,11 +416,12 @@ handling. If the `Result` is an `Ok` value, this method’s behavior is similar
to `unwrap`: it returns the inner value `Ok` is wrapping. However, if the value
is an `Err` value, this method calls the code in the *closure*, which is an
anonymous function we define and pass as an argument to `unwrap_or_else`. We’ll
cover closures in more detail in Chapter 13. For now, you just need to know
that `unwrap_or_else` will pass the inner value of the `Err`, which in this
case is the static string `not enough arguments` that we added in Listing 12-9,
to our closure in the argument `err` that appears between the vertical pipes.
The code in the closure can then use the `err` value when it runs.
cover closures in more detail in [Chapter 13][ch13]<!-- ignore -->. For now,
you just need to know that `unwrap_or_else` will pass the inner value of the
`Err`, which in this case is the static string `not enough arguments` that we
added in Listing 12-9, to our closure in the argument `err` that appears
between the vertical pipes. The code in the closure can then use the `err`
value when it runs.

We’ve added a new `use` line to bring `process` from the standard library into
scope. The code in the closure that will be run in the error case is only two
Expand Down Expand Up @@ -519,16 +520,17 @@ returned the unit type, `()`, and we keep that as the value returned in the

For the error type, we used the *trait object* `Box<dyn Error>` (and we’ve
brought `std::error::Error` into scope with a `use` statement at the top).
We’ll cover trait objects in Chapter 17. For now, just know that `Box<dyn
Error>` means the function will return a type that implements the `Error`
trait, but we don’t have to specify what particular type the return value
will be. This gives us flexibility to return error values that may be of
different types in different error cases. The `dyn` keyword is short for
“dynamic.”
We’ll cover trait objects in [Chapter 17][ch17]<!-- ignore -->. For now, just
know that `Box<dyn Error>` means the function will return a type that
implements the `Error` trait, but we don’t have to specify what particular type
the return value will be. This gives us flexibility to return error values that
may be of different types in different error cases. The `dyn` keyword is short
for “dynamic.”

Second, we’ve removed the call to `expect` in favor of the `?` operator, as we
talked about in Chapter 9. Rather than `panic!` on an error, `?` will return
the error value from the current function for the caller to handle.
talked about in [Chapter 9][ch9-question-mark]<!-- ignore -->. Rather than
`panic!` on an error, `?` will return the error value from the current function
for the caller to handle.

Third, the `run` function now returns an `Ok` value in the success case. We’ve
declared the `run` function’s success type as `()` in the signature, which
Expand Down Expand Up @@ -671,3 +673,9 @@ have been difficult with the old code but is easy with the new code: we’ll
write some tests!

[the-static-lifetime]: ch10-03-lifetime-syntax.html#the-static-lifetime
[ch13]: ch13-00-functional-features.html
[ch9-custom-types]: ch09-03-to-panic-or-not-to-panic.html#creating-custom-types-for-validation
[ch9-error-guidelines]: ch09-03-to-panic-or-not-to-panic.html#guidelines-for-error-handling
[ch9-result]: ch09-02-recoverable-errors-with-result.html
[ch17]: ch17-00-oop.html
[ch9-question-mark]: ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
31 changes: 18 additions & 13 deletions src/ch12-04-testing-the-librarys-functionality.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ lines that match the query. We’ll add this functionality in a function called
Because we don’t need them anymore, let’s remove the `println!` statements from
*src/lib.rs* and *src/main.rs* that we used to check the program’s behavior.
Then, in *src/lib.rs*, we’ll add a `tests` module with a test function, as we
did in Chapter 11. The test function specifies the behavior we want the
`search` function to have: it will take a query and the text to search for the
query in, and it will return only the lines from the text that contain the
query. Listing 12-15 shows this test, which won’t compile yet.
did in [Chapter 11][ch11-anatomy]<!-- ignore -->. The test function specifies
the behavior we want the `search` function to have: it will take a query and
the text to search for the query in, and it will return only the lines from the
text that contain the query. Listing 12-15 shows this test, which won’t compile
yet.

<span class="filename">Filename: src/lib.rs</span>

Expand Down Expand Up @@ -91,10 +92,11 @@ function so our test will compile</span>

Notice that we need an explicit lifetime `'a` defined in the signature of
`search` and used with the `contents` argument and the return value. Recall in
Chapter 10 that the lifetime parameters specify which argument lifetime is
connected to the lifetime of the return value. In this case, we indicate that
the returned vector should contain string slices that reference slices of the
argument `contents` (rather than the argument `query`).
[Chapter 10][ch10-lifetimes]<!-- ignore --> that the lifetime parameters
specify which argument lifetime is connected to the lifetime of the return
value. In this case, we indicate that the returned vector should contain string
slices that reference slices of the argument `contents` (rather than the
argument `query`).

In other words, we tell Rust that the data returned by the `search` function
will live as long as the data passed into the `search` function in the
Expand Down Expand Up @@ -194,9 +196,9 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
</span>

The `lines` method returns an iterator. We’ll talk about iterators in depth in
Chapter 13, but recall that you saw this way of using an iterator in Listing
3-5, where we used a `for` loop with an iterator to run some code on each item
in a collection.
[Chapter 13][ch13]<!-- ignore -->, but recall that you saw this way of using an
iterator in [Listing 3-5][ch3-iter]<!-- ignore -->, where we used a `for` loop
with an iterator to run some code on each item in a collection.

#### Searching Each Line for the Query

Expand Down Expand Up @@ -264,8 +266,8 @@ At this point, we could consider opportunities for refactoring the
implementation of the search function while keeping the tests passing to
maintain the same functionality. The code in the search function isn’t too bad,
but it doesn’t take advantage of some useful features of iterators. We’ll
return to this example in Chapter 13, where we’ll explore iterators in detail,
and look at how to improve it.
return to this example in [Chapter 13][ch13]<!-- ignore -->, where we’ll
explore iterators in detail, and look at how to improve it.

#### Using the `search` Function in the `run` Function

Expand Down Expand Up @@ -331,3 +333,6 @@ useful when you’re writing command line programs.

[validating-references-with-lifetimes]:
ch10-03-lifetime-syntax.html#validating-references-with-lifetimes
[ch11-anatomy]: ch11-01-writing-tests.html#the-anatomy-of-a-test-function
[ch10-lifetimes]: ch10-03-lifetime-syntax.html
[ch3-iter]: ch03-05-control-flow.html#looping-through-a-collection-with-for

0 comments on commit db919bc

Please sign in to comment.