From db919bc6bb9071566e9c4f05053672133eaac33e Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Mon, 15 Apr 2019 20:09:10 -0400 Subject: [PATCH] Link to chapters mentioned in chapter 12 Fixes #1887. --- src/ch12-00-an-io-project.md | 23 ++++-- ...h12-01-accepting-command-line-arguments.md | 27 +++---- ...improving-error-handling-and-modularity.md | 72 ++++++++++--------- ...2-04-testing-the-librarys-functionality.md | 31 ++++---- 4 files changed, 90 insertions(+), 63 deletions(-) diff --git a/src/ch12-00-an-io-project.md b/src/ch12-00-an-io-project.md index 0b84111a85..5802d97984 100644 --- a/src/ch12-00-an-io-project.md +++ b/src/ch12-00-an-io-project.md @@ -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]) +* Using vectors and strings (collections, [Chapter 8][ch8]) +* Handling errors ([Chapter 9][ch9]) +* Using traits and lifetimes where appropriate ([Chapter 10][ch10]) +* Writing tests ([Chapter 11][ch11]) We’ll also briefly introduce closures, iterators, and trait objects, which -Chapters 13 and 17 will cover in detail. +Chapters [13][ch13] and [17][ch17] 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 diff --git a/src/ch12-01-accepting-command-line-arguments.md b/src/ch12-01-accepting-command-line-arguments.md index 6a8116b14f..50d17ae5d1 100644 --- a/src/ch12-01-accepting-command-line-arguments.md +++ b/src/ch12-01-accepting-command-line-arguments.md @@ -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]. 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. @@ -54,13 +54,13 @@ a vector and printing them 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], 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 > @@ -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 diff --git a/src/ch12-03-improving-error-handling-and-modularity.md b/src/ch12-03-improving-error-handling-and-modularity.md index 005a1437c0..5f014d7f98 100644 --- a/src/ch12-03-improving-error-handling-and-modularity.md +++ b/src/ch12-03-improving-error-handling-and-modularity.md @@ -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], 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 @@ -304,13 +304,13 @@ fn new(args: &[String]) -> Config { Listing 12-8: Adding a check for the number of arguments -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], 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: @@ -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]. Instead, we +can use the other technique you learned about in Chapter 9—[returning a +`Result`][ch9-result] that indicates either success or an error. #### Returning a `Result` from `new` Instead of Calling `panic!` @@ -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]. 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 @@ -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` (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` 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]. For now, just +know that `Box` 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]. 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 @@ -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 diff --git a/src/ch12-04-testing-the-librarys-functionality.md b/src/ch12-04-testing-the-librarys-functionality.md index 99b561d132..2d1eeb04d6 100644 --- a/src/ch12-04-testing-the-librarys-functionality.md +++ b/src/ch12-04-testing-the-librarys-functionality.md @@ -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]. 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. Filename: src/lib.rs @@ -91,10 +92,11 @@ function so our test will compile 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] 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 @@ -194,9 +196,9 @@ pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { 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], but recall that you saw this way of using an +iterator in [Listing 3-5][ch3-iter], 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 @@ -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], where we’ll +explore iterators in detail, and look at how to improve it. #### Using the `search` Function in the `run` Function @@ -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