diff --git a/nostarch/chapter01.md b/nostarch/chapter01.md index 0d81803a9..66aca48c3 100644 --- a/nostarch/chapter01.md +++ b/nostarch/chapter01.md @@ -135,7 +135,7 @@ $ echo $PATH If that’s all correct and Rust still isn’t working, there are a number of places you can get help. Find out how to get in touch with other Rustaceans (a -silly nickname we call ourselves) on the community page at +silly nickname we call ourselves) on the community page at *https://www.rust-lang.org/community*. ### Updating and Uninstalling @@ -304,7 +304,7 @@ fn main() { ``` These lines define a function named `main`. The `main` function is special: it -is always the first code that runs in every executable Rust program. Here, the +is always the first code that runs in every executable Rust program. Here, the first line declares a function named `main` that has no parameters and returns nothing. If there were parameters, they would go inside the parentheses `()`. @@ -359,7 +359,7 @@ If you have a C or C++ background, you’ll notice that this is similar to `gcc` or `clang`. After compiling successfully, Rust outputs a binary executable. On Linux, macOS, and PowerShell on Windows, you can see the executable by -entering the `ls` command in your shell. +entering the `ls` command in your shell: ``` $ ls @@ -405,7 +405,7 @@ If you’re more familiar with a dynamic language, such as Ruby, Python, or JavaScript, you might not be used to compiling and running a program as separate steps. Rust is an *ahead-of-time* *compiled* language, meaning you can compile a program and give the executable to someone else, and they can run it -even without having Rust installed. If you give someone a *.rb*, *.py*, or +even without having Rust installed. If you give someone a *.rb*, *.py*, or *.js* file, they need to have a Ruby, Python, or JavaScript implementation installed (respectively). But in those languages, you only need one command to compile and run your program. Everything is a trade-off in language design. @@ -470,7 +470,7 @@ It has also initialized a new Git repository along with a *.gitignore* file. Git files won’t be generated if you run `cargo` `new` within an existing Git repository; you can override this behavior by using `cargo` `new` `--vcs=git`. -> NoteGit is a common version control system. You can change `cargo` `new` to +> NoteGit is a common version control system. You can change `cargo` `new` to use a different version control system or no version control system by using the `--vcs` flag. Run `cargo` `new` `--help` to see the available options. @@ -505,7 +505,7 @@ edition = "2021" Contents of *Cargo.toml* generated by `cargo` `new` -This file is in the *TOML* (*Tom’s* *Obvious,* *Minimal* *Language*) format, +This file is in the *TOML* (*Tom’s* *Obvious,* *Minimal* *Language*) format, which is Cargo’s configuration format. The first line, `[package]`, is a section heading that indicates that the @@ -513,8 +513,8 @@ following statements are configuring a package. As we add more information to this file, we’ll add other sections. The next three lines set the configuration information Cargo needs to compile -your program: the name, the version, and the edition of Rust to use. We’ll -talk about the `edition` key in Appendix E. +your program: the name, the version, and the edition of Rust to use. We’ll talk +about the `edition` key in Appendix E. The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Rust, packages of code are referred to as diff --git a/nostarch/chapter03.md b/nostarch/chapter03.md index a5c7d37e2..2bb7b8e90 100644 --- a/nostarch/chapter03.md +++ b/nostarch/chapter03.md @@ -34,7 +34,7 @@ can find a list of the keywords in Appendix A. ## Variables and Mutability -As mentioned in “Storing Values with Variables” on page XX, by default +As mentioned in “Storing Values with Variables” on page XX, by default, variables are immutable. This is one of many nudges Rust gives you to write your code in a way that takes advantage of the safety and easy concurrency that Rust offers. However, you still have the option to make your variables mutable. @@ -244,15 +244,15 @@ program). Rust’s naming convention for constants is to use all uppercase with underscores between words. The compiler is able to evaluate a limited set of operations at compile time, which lets us choose to write out this value in a way that’s easier to understand and verify, rather than setting this constant -to the value 10,800. See the Rust Reference’s section on constant evaluation at -*https://doc.rust-lang.org/reference/const_eval.html* for more information on -what operations can be used when declaring constants. +to the value `10,800`. See the Rust Reference’s section on constant evaluation +at *https://doc.rust-lang.org/reference/const_eval.html* for more information +on what operations can be used when declaring constants. Constants are valid for the entire time a program runs, within the scope in which they were declared. This property makes constants useful for values in your application domain that multiple parts of the program might need to know about, such as the maximum number of points any player of a game is allowed to -earn or the speed of light. +earn, or the speed of light. Naming hardcoded values used throughout your program as constants is useful in conveying the meaning of that value to future maintainers of the code. It also @@ -641,7 +641,7 @@ Unmatched: BoxListBullet Rust also has two primitive types for *floating-point numbers*, which are numbers with decimal points. Rust’s floating-point types are `f32` and `f64`, which are 32 bits and 64 bits in size, respectively. The default type is `f64` -because on modern CPUs it’s roughly the same speed as `f32` but is capable of +because on modern CPUs, it’s roughly the same speed as `f32` but is capable of more precision. All floating-point types are signed. Here’s an example that shows floating-point numbers in action: @@ -1151,9 +1151,9 @@ fn main() { ``` This code compiles successfully. If you run this code using `cargo run` and -enter 0, 1, 2, 3, or 4, the program will print out the corresponding value at -that index in the array. If you instead enter a number past the end of the -array, such as 10, you’ll see output like this: +enter `0`, `1`, `2`, `3`, or `4`, the program will print out the corresponding +value at that index in the array. If you instead enter a number past the end of +the array, such as `10`, you’ll see output like this: ``` thread 'main' panicked at 'index out of bounds: the len is 5 but the index is @@ -1269,8 +1269,8 @@ Another function. ``` The lines execute in the order in which they appear in the `main` function. -First, the “Hello, world!” message prints, and then `another_function` is -called and its message is printed. +First the “Hello, world!” message prints, and then `another_function` is called +and its message is printed. ### Parameters @@ -1897,10 +1897,10 @@ discuss in “Publishing a Crate to Crates.io” on page XX. ## Control Flow -The ability to run some code depending on whether a condition is true and to -run some code repeatedly while a condition is true are basic building blocks in -most programming languages. The most common constructs that let you control the -flow of execution of Rust code are `if` expressions and loops. +The ability to run some code depending on whether a condition is `true` and to +run some code repeatedly while a condition is `true` are basic building blocks +in most programming languages. The most common constructs that let you control +the flow of execution of Rust code are `if` expressions and loops. ### if Expressions @@ -1952,7 +1952,7 @@ fn main() { All `if` expressions start with the keyword `if`, followed by a condition. In this case, the condition checks whether or not the variable `number` has a value less than 5. We place the block of code to execute if the condition is -true immediately after the condition inside curly brackets. Blocks of code +`true` immediately after the condition inside curly brackets. Blocks of code associated with the conditions in `if` expressions are sometimes called *arms*, just like the arms in `match` expressions that we discussed in “Comparing the Guess to the Secret Number” on page XX. @@ -2204,7 +2204,7 @@ When this program executes, it checks each `if` expression in turn and executes the first body for which the condition evaluates to `true`. Note that even though 6 is divisible by 2, we don’t see the output `number is divisible by 2`, nor do we see the `number is not divisible by 4, 3, or 2` text from the `else` -block. That’s because Rust only executes the block for the first true +block. That’s because Rust only executes the block for the first `true` condition, and once it finds one, it doesn’t even check the rest. Using too many `else if` expressions can clutter your code, so if you have more @@ -2396,7 +2396,7 @@ fn main() { When we run this program, we’ll see `again!` printed over and over continuously until we stop the program manually. Most terminals support the keyboard -shortcut ctrl-c to interrupt a program that is stuck in a continual loop. Give +shortcut ctrl-C to interrupt a program that is stuck in a continual loop. Give it a try: ``` @@ -2435,7 +2435,7 @@ again! ^Cagain! ``` -The symbol `^C` represents where you pressed ctrl-c. You may or may not see the +The symbol `^C` represents where you pressed ctrl-C. You may or may not see the word `again!` printed after the `^C`, depending on where the code was in the loop when it received the interrupt signal. @@ -2516,7 +2516,7 @@ the loop. On every iteration of the loop, we add `1` to the `counter` variable, and then check whether the `counter` is equal to `10`. When it is, we use the `break` keyword with the value `counter * 2`. After the loop, we use a semicolon to end the statement that assigns the value to `result`. Finally, we -print the value in `result`, which in this case is 20. +print the value in `result`, which in this case is `20`. #### Loop Labels to Disambiguate Between Multiple Loops @@ -2666,7 +2666,7 @@ End count = 2 #### Conditional Loops with while A program will often need to evaluate a condition within a loop. While the -condition is true, the loop runs. When the condition ceases to be true, the +condition is `true`, the loop runs. When the condition ceases to be `true`, the program calls `break`, stopping the loop. It’s possible to implement behavior like this using a combination of `loop`, `if`, `else`, and `break`; you could try that now in a program, if you’d like. However, this pattern is so common @@ -2778,8 +2778,8 @@ Looping through each element of a collection using a `while` loop Here, the code counts up through the elements in the array. It starts at index `0`, and then loops until it reaches the final index in the array (that is, -when `index < 5` is no longer true). Running this code will print every element -in the array: +when `index < 5` is no longer `true`). Running this code will print every +element in the array: ``` $ cargo run diff --git a/nostarch/chapter04.md b/nostarch/chapter04.md index 087b18cb6..740d1a721 100644 --- a/nostarch/chapter04.md +++ b/nostarch/chapter04.md @@ -16,7 +16,7 @@ features: borrowing, slices, and how Rust lays data out in memory. ## What Is Ownership? -*Ownership* is a set of rules that governs how a Rust program manages memory. +*Ownership* is a set of rules that govern how a Rust program manages memory. All programs have to manage the way they use a computer’s memory while running. Some languages have garbage collection that regularly looks for no-longer-used memory as the program runs; in other languages, the programmer must explicitly @@ -197,9 +197,9 @@ let s = String::from("hello"); The double colon `::` operator allows us to namespace this particular `from` function under the `String` type rather than using some sort of name like -`string_from`. We’ll discuss this syntax more in “Method Syntax” on page XX and -when we talk about namespacing with modules in “Paths for Referring to an Item -in the Module Tree” on page XX. +`string_from`. We’ll discuss this syntax more in “Method Syntax” on page XX, +and when we talk about namespacing with modules in “Paths for Referring to an +Item in the Module Tree” on page XX. This kind of string *can* be mutated: @@ -378,7 +378,7 @@ of the memory safety bugs we mentioned previously. Freeing memory twice can lead to memory corruption, which can potentially lead to security vulnerabilities. -To ensure memory safety, after the line `let s2 =` `s1``;`, Rust considers `s1` +To ensure memory safety, after the line `let s2 = s1``;`, Rust considers `s1` as no longer valid. Therefore, Rust doesn’t need to free anything when `s1` goes out of scope. Check out what happens when you try to use `s1` after `s2` is created; it won’t work: @@ -423,7 +423,7 @@ error[E0382]: borrow of moved value: `s1` ``` ``` -does not implement the `Copy` trait + does not implement the `Copy` trait ``` ``` @@ -464,7 +464,7 @@ In addition, there’s a design choice that’s implied by this: Rust will never automatically create “deep” copies of your data. Therefore, any *automatic* copying can be assumed to be inexpensive in terms of runtime performance. -#### Variables and Data Interacting With Clone +#### Variables and Data Interacting with Clone If we *do* want to deeply copy the heap data of the `String`, not just the stack data, we can use a common method called `clone`. We’ll discuss method @@ -558,7 +558,9 @@ assigning a value to a variable. Passing a variable to a function will move or copy, just as assignment does. Listing 4-3 has an example with some annotations showing where variables go into and out of scope. -Filename: src/main.rs +``` +// src/main.rs +``` ``` fn main() { @@ -665,7 +667,9 @@ Returning values can also transfer ownership. Listing 4-4 shows an example of a function that returns some value, with similar annotations as those in Listing 4-3. -Filename: src/main.rs +``` +// src/main.rs +``` ``` fn main() { @@ -1045,6 +1049,9 @@ reference ``` | ------- help: consider changing this to be a mutable +``` + +``` reference: `&mut String` ``` @@ -1054,6 +1061,9 @@ reference: `&mut String` ``` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `some_string` is a `&` reference, so +``` + +``` the data it refers to cannot be borrowed as mutable ``` @@ -1485,7 +1495,9 @@ is no value for it to be borrowed from Let’s take a closer look at exactly what’s happening at each stage of our `dangle` code: -Filename: src/main.rs +``` +// src/main.rs +``` ``` fn dangle() -> &String { // dangle returns a reference to a String @@ -1655,7 +1667,9 @@ because it’s a separate value from the `String`, there’s no guarantee that i will still be valid in the future. Consider the program in Listing 4-8 that uses the `first_word` function from Listing 4-7. -Filename: src/main.rs +``` +// src/main.rs +``` ``` fn main() { @@ -1749,7 +1763,7 @@ one more than the last position in the slice. Internally, the slice data structure stores the starting position and the length of the slice, which corresponds to `ending_index` minus `starting_index`. So, in the case of `let world = &s[6..11];`, `world` would be a slice that contains a pointer to the -byte at index 6 of `s` with a length value of 5. +byte at index 6 of `s` with a length value of `5`. Figure 4-6 shows this in a diagram. @@ -1757,8 +1771,8 @@ Figure 4-6 shows this in a diagram. Unmatched: GraphicSlug Unmatched: CaptionLine - With Rust’s `..` range syntax, if you want to start at index zero, you -can drop the value before the two periods. In other words, these are equal: + With Rust’s `..` range syntax, if you want to start at index 0, you can +drop the value before the two periods. In other words, these are equal: ``` let s = String::from("hello"); diff --git a/nostarch/chapter05.md b/nostarch/chapter05.md index a6f6a2366..c42f87c45 100644 --- a/nostarch/chapter05.md +++ b/nostarch/chapter05.md @@ -829,8 +829,8 @@ Defining a `Rectangle` struct Here, we’ve defined a struct and named it `Rectangle` [1]. Inside the curly brackets, we defined the fields as `width` and `height`, both of which have -type `u32` [2]. Then in `main`, we created a particular instance of `Rectangle` -that has a width of 30 and a height of 50 [3]. +type `u32` [2]. Then, in `main`, we created a particular instance of +`Rectangle` that has a width of `30` and a height of `50` [3]. Our `area` function is now defined with one parameter, which we’ve named `rectangle`, whose type is an immutable borrow of a struct `Rectangle` instance @@ -1063,7 +1063,7 @@ call occurs in your code along with the resultant value of that expression, and returns ownership of the value. > NoteCalling the `dbg!` macro prints to the standard error console stream -(`stderr`), as opposed to `println!` which prints to the standard output +(`stderr`), as opposed to `println!`, which prints to the standard output console stream (`stdout`). We’ll talk more about `stderr` and `stdout` in “Writing Error Messages to Standard Error Instead of Standard Output” on page XX. @@ -1160,11 +1160,12 @@ take ownership of `rect1`, so we use a reference to `rect1` in the next call ``` We can see the first bit of output came from [1] where we’re debugging the -expression `30 * scale`, and its resultant value is 60 (the `Debug` formatting -implemented for integers is to print only their value). The `dbg!` call at [2] -outputs the value of `&rect1`, which is the `Rectangle` struct. This output -uses the pretty `Debug` formatting of the `Rectangle` type. The `dbg!` macro -can be really helpful when you’re trying to figure out what your code is doing! +expression `30 * scale`, and its resultant value is `60` (the `Debug` +formatting implemented for integers is to print only their value). The `dbg!` +call at [2] outputs the value of `&rect1`, which is the `Rectangle` struct. +This output uses the pretty `Debug` formatting of the `Rectangle` type. The +`dbg!` macro can be really helpful when you’re trying to figure out what your +code is doing! In addition to the `Debug` trait, Rust has provided a number of traits for us to use with the `derive` attribute that can add useful behavior to our custom @@ -1308,9 +1309,10 @@ type `Self` is an alias for the type that the `impl` block is for. Methods must have a parameter named `self` of type `Self` for their first parameter, so Rust lets you abbreviate this with only the name `self` in the first parameter spot. Note that we still need to use the `&` in front of the `self` shorthand to -indicate this method borrows the `Self` instance, just as we did in `rectangle: -&Rectangle`. Methods can take ownership of `self`, borrow `self` immutably as -we’ve done here, or borrow `self` mutably, just as they can any other parameter. +indicate that this method borrows the `Self` instance, just as we did in +`rectangle: &Rectangle`. Methods can take ownership of `self`, borrow `self` +immutably, as we’ve done here, or borrow `self` mutably, just as they can any +other parameter. We chose `&self` here for the same reason we used `&Rectangle` in the function version: we don’t want to take ownership, and we just want to read the data in @@ -1329,7 +1331,8 @@ of our code search for capabilities of `Rectangle` in various places in the library we provide. Note that we can choose to give a method the same name as one of the struct’s -fields. For example, we can define a method on `Rectangle` also named `width`: +fields. For example, we can define a method on `Rectangle` that is also named +`width`: Filename: src/main.rs @@ -1410,16 +1413,17 @@ fn main() { ``` Here, we’re choosing to make the `width` method return `true` if the value in -the instance’s `width` field is greater than 0 and `false` if the value is 0: -we can use a field within a method of the same name for any purpose. In `main`, -when we follow `rect1.width` with parentheses, Rust knows we mean the method -`width`. When we don’t use parentheses, Rust knows we mean the field `width`. +the instance’s `width` field is greater than `0` and `false` if the value is +`0`: we can use a field within a method of the same name for any purpose. In +`main`, when we follow `rect1.width` with parentheses, Rust knows we mean the +method `width`. When we don’t use parentheses, Rust knows we mean the field +`width`. Often, but not always, when we give methods with the same name as a field we want it to only return the value in the field and do nothing else. Methods like this are called *getters*, and Rust does not implement them automatically for struct fields as some other languages do. Getters are useful because you can -make the field private but the method public and thus enable read-only access +make the field private but the method public, and thus enable read-only access to that field as part of the type’s public API. We will discuss what public and private are and how to designate a field or method as public or private in Chapter 7. @@ -1433,8 +1437,8 @@ Unmatched: BoxType > In C and C++, two different operators are used for calling methods: you use `.` if you’re calling a method on the object directly and `->` if you’re calling the method on a pointer to the object and need to dereference the -pointer first. In other words, if `object` is a pointer, `object->something()` -is similar to `(*object).something()`. +pointer first. In other words, if `object` is a pointer, +`object->`something`()` is similar to `(*object).`something`()`. > Rust doesn’t have an equivalent to the `->` operator; instead, Rust has a @@ -1442,7 +1446,7 @@ feature called *automatic referencing and dereferencing*. Calling methods is one of the few places in Rust that has this behavior. -> Here’s how it works: when you call a method with `object.something()`, Rust +> Here’s how it works: when you call a method with `object.`something`()`, Rust automatically adds in `&`, `&mut`, or `*` so `object` matches the signature of the method. In other words, the following are the same: @@ -1463,9 +1467,9 @@ ownership ergonomic in practice. Let’s practice using methods by implementing a second method on the `Rectangle` struct. This time we want an instance of `Rectangle` to take another instance of `Rectangle` and return `true` if the second `Rectangle` can fit completely -within `self` (the first `Rectangle`); otherwise it should return `false`. That -is, once we’ve defined the `can_hold` method, we want to be able to write the -program shown in Listing 5-14. +within `self` (the first `Rectangle`); otherwise, it should return `false`. +That is, once we’ve defined the `can_hold` method, we want to be able to write +the program shown in Listing 5-14. Filename: src/main.rs @@ -1540,7 +1544,7 @@ fn main() { Using the as-yet-unwritten `can_hold` method The expected output would look like the following because both dimensions of -`rect2` are smaller than the dimensions of `rect1` but `rect3` is wider than +`rect2` are smaller than the dimensions of `rect1`, but `rect3` is wider than `rect1`: ``` diff --git a/nostarch/chapter06.md b/nostarch/chapter06.md index 4f641c9ae..7214b8d84 100644 --- a/nostarch/chapter06.md +++ b/nostarch/chapter06.md @@ -931,10 +931,10 @@ state value out of the `Coin` enum variant for `Quarter`. ### Matching with Option In the previous section, we wanted to get the inner `T` value out of the `Some` -case when using `Option`; we can also handle `Option` using `match` as we -did with the `Coin` enum! Instead of comparing coins, we’ll compare the -variants of `Option`, but the way that the `match` expression works remains -the same. +case when using `Option`; we can also handle `Option` using `match`, as +we did with the `Coin` enum! Instead of comparing coins, we’ll compare the +variants of `Option`, but the way the `match` expression works remains the +same. Let’s say we want to write a function that takes an `Option` and, if there’s a value inside, adds 1 to that value. If there isn’t a value inside, @@ -1109,7 +1109,7 @@ shown | ``` -Rust knows that we didn’t cover every possible case and even knows which +Rust knows that we didn’t cover every possible case, and even knows which pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last possibility in order for the code to be valid. Especially in the case of `Option`, when Rust prevents us from forgetting to explicitly handle the @@ -1340,7 +1340,7 @@ The syntax `if let` takes a pattern and an expression separated by an equal sign. It works the same way as a `match`, where the expression is given to the `match` and the pattern is its first arm. In this case, the pattern is `Some(max)`, and the `max` binds to the value inside the `Some`. We can then -use `max` in the body of the `if let` block in the same way as we used `max` in +use `max` in the body of the `if let` block in the same way we used `max` in the corresponding `match` arm. The code in the `if let` block isn’t run if the value doesn’t match the pattern. diff --git a/nostarch/chapter07.md b/nostarch/chapter07.md index fb6398cf7..9fed26d99 100644 --- a/nostarch/chapter07.md +++ b/nostarch/chapter07.md @@ -258,7 +258,7 @@ Unmatched: BoxCode ## Defining Modules to Control Scope and Privacy In this section, we’ll talk about modules and other parts of the module system, -namely *paths* that allow you to name items; the `use` keyword that brings a +namely *paths*, which allow you to name items; the `use` keyword that brings a path into scope; and the `pub` keyword to make items public. We’ll also discuss the `as` keyword, external packages, and the glob operator. @@ -526,9 +526,9 @@ filesystem equivalent would be using the path that the path is relative. Choosing whether to use a relative or absolute path is a decision you’ll make -based on your project, and depends on whether you’re more likely to move item -definition code separately from or together with the code that uses the item. -For example, if we moved the `front_of_house` module and the +based on your project, and it depends on whether you’re more likely to move +item definition code separately from or together with the code that uses the +item. For example, if we moved the `front_of_house` module and the `eat_at_restaurant` function into a module named `customer_experience`, we’d need to update the absolute path to `add_to_waitlist`, but the relative path would still be valid. However, if we moved the `eat_at_restaurant` function @@ -927,7 +927,7 @@ Consider the code in Listing 7-8 that models the situation in which a chef fixes an incorrect order and personally brings it out to the customer. The function `fix_incorrect_order` defined in the `back_of_house` module calls the function `deliver_order` defined in the parent module by specifying the path to -`deliver_order` starting with `super`. +`deliver_order`, starting with `super`. Filename: src/lib.rs @@ -1381,7 +1381,7 @@ the shortcut in the parent module with `super::hosting` within the child In Listing 7-11, you might have wondered why we specified `use crate::front_of_house::hosting` and then called `hosting::add_to_waitlist` in -`eat_at_restaurant` rather than specifying the `use` path all the way out to +`eat_at_restaurant`, rather than specifying the `use` path all the way out to the `add_to_waitlist` function to achieve the same result, as in Listing 7-13. Filename: src/lib.rs @@ -1529,7 +1529,7 @@ parent modules. As you can see, using the parent modules distinguishes the two `Result` types. If instead we specified `use std::fmt::Result` and `use std::io::Result`, we’d -have two `Result` types in the same scope and Rust wouldn’t know which one we +have two `Result` types in the same scope, and Rust wouldn’t know which one we meant when we used `Result`. ### Providing New Names with the as Keyword @@ -1678,7 +1678,7 @@ rand = "0.8.5" ``` Adding `rand` as a dependency in *Cargo.toml* tells Cargo to download the -`rand` package and any dependencies from *https://crates.io* and make `rand` +`rand` package and any dependencies from *https://crates.io*, and make `rand` available to our project. Then, to bring `rand` definitions into the scope of our package, we added a @@ -1931,7 +1931,7 @@ pub fn add_to_waitlist() {} If we instead put *hosting.rs* in the *src* directory, the compiler would expect the *hosting.rs* code to be in a `hosting` module declared in the crate root, and not declared as a child of the `front_of_house` module. The -compiler’s rules for which files to check for which modules’ code means the +compiler’s rules for which files to check for which modules’ code mean the directories and files more closely match the module tree. diff --git a/nostarch/chapter08.md b/nostarch/chapter08.md index 49993a13b..6bef0c2da 100644 --- a/nostarch/chapter08.md +++ b/nostarch/chapter08.md @@ -118,7 +118,7 @@ we don’t need the `Vec` annotation. ### Reading Elements of Vectors -There are two ways to reference a value stored in a vector: via indexing or +There are two ways to reference a value stored in a vector: via indexing or by using the `get` method. In the following examples, we’ve annotated the types of the values that are returned from these functions for extra clarity. @@ -450,7 +450,7 @@ store in a vector, the enum technique won’t work. Instead, you can use a trait object, which we’ll cover in Chapter 17. Now that we’ve discussed some of the most common ways to use vectors, be sure -to review the API documentation for all the many useful methods defined on +to review the API documentation for all of the many useful methods defined on `Vec` by the standard library. For example, in addition to `push`, a `pop` method removes and returns the last element. @@ -567,8 +567,6 @@ let s = data.to_string(); let s = "initial contents".to_string(); ``` -PROD: I couldn’t get the following listing caption to format correctly. - Using the `to_string` method to create a `String` from a string literal @@ -688,7 +686,7 @@ If the `push_str` method took ownership of `s2`, we wouldn’t be able to print its value on the last line. However, this code works as we’d expect! The `push` method takes a single character as a parameter and adds it to the -`String`. Listing 8-17 adds the letter “l” to a `String` using the `push` +`String`. Listing 8-17 adds the letter *l* to a `String` using the `push` method. ``` @@ -740,7 +738,7 @@ bits of the `+` operator. First, `s2` has an `&`, meaning that we’re adding a *reference* of the second string to the first string. This is because of the `s` parameter in the `add` -function: we can only add a `&str` to a `String`; we can’t add two `String` +function: we can only add a `&``str` to a `String`; we can’t add two `String` values together. But wait—the type of `&s2` is `&String`, not `&str`, as specified in the second parameter to `add`. So why does Listing 8-18 compile? @@ -784,8 +782,8 @@ let s = s1 + "-" + &s2 + "-" + &s3; ``` At this point, `s` will be `tic-tac-toe`. With all of the `+` and `"` -characters, it’s difficult to see what’s going on. For more complicated string -combining, we can instead use the `format!` macro: +characters, it’s difficult to see what’s going on. For combining strings in +more complicated ways, we can instead use the `format!` macro: ``` let s1 = String::from("tic"); @@ -828,7 +826,7 @@ let s1 = String::from("hello"); let h = s1[0]; ``` -Attempting to use indexing syntax with a String +Attempting to use indexing syntax with a `String` Unmatched: BodyContinued @@ -877,10 +875,10 @@ encoded UTF-8 example strings from Listing 8-14. First, this one: let hello = String::from("Hola"); ``` -In this case, `len` will be 4, which means the vector storing the string +In this case, `len` will be `4`, which means the vector storing the string `"``Hola``"` is 4 bytes long. Each of these letters takes one byte when encoded in UTF-8. The following line, however, may surprise you (note that this string -begins with the capital Cyrillic letter Ze, not the Arabic number 3): +begins with the capital Cyrillic letter *Ze*, not the Arabic number 3): ``` let hello = String::from("Здравствуйте"); @@ -1064,7 +1062,7 @@ Unmatched: BodyContinued But be sure to remember that valid Unicode scalar values may be made up of more than one byte. -Getting grapheme clusters from strings as with the Devanagari script is +Getting grapheme clusters from strings, as with the Devanagari script, is complex, so this functionality is not provided by the standard library. Crates are available at *https://crates.io* if this is the functionality you need. @@ -1093,8 +1091,8 @@ The last of our common collections is the *hash map*. The type `HashMap` stores a mapping of keys of type `K` to values of type `V` using a *hashing function*, which determines how it places these keys and values into memory. Many programming languages support this kind of data structure, but they often -use a different name, such as hash, map, object, hash table, dictionary, or -associative array, just to name a few. +use a different name, such as *hash*, *map*, *object*, *hash table*, +*dictionary*, or *associative array*, just to name a few. Hash maps are useful when you want to look up data not by using an index, as you can with vectors, but by using a key that can be of any type. For example, @@ -1309,8 +1307,8 @@ least as long as the hash map is valid. We’ll talk more about these issues in Although the number of key and value pairs is growable, each unique key can only have one value associated with it at a time (but not vice versa: for -example, both the Blue team and the Yellow team could have value 10 stored in -the `scores` hash map). +example, both the Blue team and the Yellow team could have the value `10` +stored in the `scores` hash map). When you want to change the data in a hash map, you have to decide how to handle the case when a key already has a value assigned. You could replace the @@ -1374,7 +1372,7 @@ Hash maps have a special API for this called `entry` that takes the key you want to check as a parameter. The return value of the `entry` method is an enum called `Entry` that represents a value that might or might not exist. Let’s say we want to check whether the key for the Yellow team has a value associated -with it. If it doesn’t, we want to insert the value 50, and the same for the +with it. If it doesn’t, we want to insert the value `50`, and the same for the Blue team. Using the `entry` API, the code looks like Listing 8-24. ``` @@ -1523,9 +1521,9 @@ some exercises you should now be equipped to solve: the value in the middle position) and mode (the value that occurs most often; a hash map will be helpful here) of the list. 1. Convert strings to pig latin. The first consonant of each word is moved to -the end of the word and “ay” is added, so “first” becomes “irst-fay.” Words -that start with a vowel have “hay” added to the end instead (“apple” becomes -“apple-hay”). Keep in mind the details about UTF-8 encoding! +the end of the word and *ay* is added, so *first* becomes *irst-fay*. Words +that start with a vowel have *hay* added to the end instead (*apple* becomes +*apple-hay*). Keep in mind the details about UTF-8 encoding! 1. Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in a company; for example, “Add Sally to Engineering” or “Add Amir to Sales.” Then let the user retrieve a list of all diff --git a/nostarch/chapter09.md b/nostarch/chapter09.md index fce548231..356c1e7cf 100644 --- a/nostarch/chapter09.md +++ b/nostarch/chapter09.md @@ -1,8 +1,3 @@ - [TOC] @@ -180,7 +175,7 @@ wrote. That’s the spot where the problem originated. The lines above that spot are code that your code has called; the lines below are code that called your code. These before-and-after lines might include core Rust code, standard library code, or crates that you’re using. Let’s try getting a backtrace by -setting the `RUST_BACKTRACE` environment variable to any value except 0. +setting the `RUST_BACKTRACE` environment variable to any value except `0`. Listing 9-2 shows output similar to what you’ll see. ``` @@ -434,7 +429,15 @@ fn main() { ``` ``` - Err(error) => panic!("Problem opening the file: {:?}", error), + Err(error) => { +``` + +``` + panic!("Problem opening the file: {:?}", error); +``` + +``` + } ``` ``` @@ -483,7 +486,7 @@ However, we want to take different actions for different failure reasons. If `File::open` failed because the file doesn’t exist, we want to create the file and return the handle to the new file. If `File::open` failed for any other reason—for example, because we didn’t have permission to open the file—we still -want the code to `panic!` in the same way it did in Listing 9-4. For this we +want the code to `panic!` in the same way it did in Listing 9-4. For this, we add an inner `match` expression, shown in Listing 9-5. Filename: src/main.rs @@ -525,19 +528,39 @@ fn main() { ``` ``` - ErrorKind::NotFound => match File::create("hello.txt") { + ErrorKind::NotFound => { ``` ``` - Ok(fc) => fc, + match File::create("hello.txt") { ``` ``` - Err(e) => panic!("Problem creating the file: {:?}", e), + Ok(fc) => fc, ``` ``` - }, + Err(e) => panic!( +``` + +``` + "Problem creating the file: {:?}", +``` + +``` + e +``` + +``` + ), +``` + +``` + } +``` + +``` + } ``` ``` @@ -545,7 +568,19 @@ fn main() { ``` ``` - panic!("Problem opening the file: {:?}", other_error); + panic!( +``` + +``` + "Problem opening the file: {:?}", +``` + +``` + other_error +``` + +``` + ); ``` ``` @@ -593,7 +628,9 @@ concise than using `match` when handling `Result` values in your code. For example, here’s another way to write the same logic as shown in Listing 9-5, this time using closures and the `unwrap_or_else` method: -Filename: src/main.rs +``` +// src/main.rs +``` ``` use std::fs::File; @@ -850,8 +887,8 @@ This function can be written in a much shorter way, but we’re going to start b doing a lot of it manually in order to explore error handling; at the end, we’ll show the shorter way. Let’s look at the return type of the function first: `Result` [1]. This means the function is returning a -value of the type `Result` where the generic parameter `T` has been -filled in with the concrete type `String`, and the generic type `E` has been +value of the type `Result`, where the generic parameter `T` has been +filled in with the concrete type `String` and the generic type `E` has been filled in with the concrete type `io::Error`. If this function succeeds without any problems, the code that calls this @@ -1180,7 +1217,7 @@ function that returns an `Option`. The behavior of the `?` operator when called on an `Option` is similar to its behavior when called on a `Result`: if the value is `None`, the `None` will be returned early from the function at that point. If the value is `Some`, the value inside the `Some` is the -resultant value of the expression and the function continues. Listing 9-11 has +resultant value of the expression, and the function continues. Listing 9-11 has an example of a function that finds the last character of the first line in the given text. @@ -1375,7 +1412,7 @@ valid IP address. If the IP address string came from a user rather than being hardcoded into the program and therefore *did* have a possibility of failure, we’d definitely want to handle the `Result` in a more robust way instead. Mentioning the assumption that this IP address is hardcoded will prompt us to -change `expect` to better error-handling code if in the future, we need to get +change `expect` to better error-handling code if, in the future, we need to get the IP address from some other source instead. ### Guidelines for Error Handling @@ -1416,7 +1453,7 @@ an out-of-bounds memory access: trying to access memory that doesn’t belong to the current data structure is a common security problem. Functions often have *contracts*: their behavior is only guaranteed if the inputs meet particular requirements. Panicking when the contract is violated makes sense because a -contract violation always indicates a caller-side bug and it’s not a kind of +contract violation always indicates a caller-side bug, and it’s not a kind of error you want the calling code to have to explicitly handle. In fact, there’s no reasonable way for calling code to recover; the calling *programmers* need to fix the code. Contracts for a function, especially when a violation will @@ -1445,8 +1482,8 @@ numbers before checking it against our secret number; we only validated that the guess was positive. In this case, the consequences were not very dire: our output of “Too high” or “Too low” would still be correct. But it would be a useful enhancement to guide the user toward valid guesses and have different -behavior when a user guesses a number that’s out of range versus when a user -types, for example, letters instead. +behavior when the user guesses a number that’s out of range versus when the +user types, for example, letters instead. One way to do this would be to parse the guess as an `i32` instead of only a `u32` to allow potentially negative numbers, and then add a check for the diff --git a/nostarch/chapter10.md b/nostarch/chapter10.md index 15b37a5a7..3f7e78378 100644 --- a/nostarch/chapter10.md +++ b/nostarch/chapter10.md @@ -17,8 +17,8 @@ when compiling and running the code. Functions can take parameters of some generic type, instead of a concrete type like `i32` or `String`, in the same way they take parameters with unknown values to run the same code on multiple concrete values. In fact, we’ve already -used generics in Chapter 6 with `Option`, Chapter 8 with `Vec` and -`HashMap`, and Chapter 9 with `Result`. In this chapter, you’ll +used generics in Chapter 6 with `Option`, in Chapter 8 with `Vec` and +`HashMap`, and in Chapter 9 with `Result`. In this chapter, you’ll explore how to define your own types, functions, and methods with generics! First we’ll review how to extract a function to reduce code duplication. We’ll @@ -341,7 +341,7 @@ In summary, here are the steps we took to change the code from Listing 10-2 to Listing 10-3: 1. Identify duplicate code. -1. Extract the duplicate code into the body of the function and specify the +1. Extract the duplicate code into the body of the function, and specify the inputs and return values of that code in the function signature. 1. Update the two instances of duplicated code to call the function instead. Next, we’ll use these same steps with generics to reduce code duplication. In @@ -524,7 +524,7 @@ To parameterize the types in a new single function, we need to name the type parameter, just as we do for the value parameters to a function. You can use any identifier as a type parameter name. But we’ll use `T` because, by convention, type parameter names in Rust are short, often just one letter, and -Rust’s type-naming convention is CamelCase. Short for “type,” `T` is the +Rust’s type-naming convention is CamelCase. Short for *type*, `T` is the default choice of most Rust programmers. When we use a parameter in the body of the function, we have to declare the @@ -800,9 +800,9 @@ fn main() { The fields `x` and `y` must be the same type because both have the same generic data type `T`. -In this example, when we assign the integer value 5 to `x`, we let the compiler -know that the generic type `T` will be an integer for this instance of -`Point`. Then when we specify 4.0 for `y`, which we’ve defined to have the +In this example, when we assign the integer value `5` to `x`, we let the +compiler know that the generic type `T` will be an integer for this instance of +`Point`. Then when we specify `4.0` for `y`, which we’ve defined to have the same type as `x`, we’ll get a type mismatch error like this: ``` @@ -1286,9 +1286,9 @@ at runtime. ## Traits: Defining Shared Behavior -A *trait* defines functionality a particular type has and can share with other -types. We can use traits to define shared behavior in an abstract way. We can -use *trait bounds* to specify that a generic type can be any type that has +A *trait* defines the functionality a particular type has and can share with +other types. We can use traits to define shared behavior in an abstract way. We +can use *trait bounds* to specify that a generic type can be any type that has certain behavior. > NoteTraits are similar to a feature often called *interfaces* in other @@ -1303,7 +1303,7 @@ define a set of behaviors necessary to accomplish some purpose. For example, let’s say we have multiple structs that hold various kinds and amounts of text: a `NewsArticle` struct that holds a news story filed in a -particular location and a `Tweet` that can have at most 280 characters along +particular location and a `Tweet` that can have, at most, 280 characters along with metadata that indicates whether it was a new tweet, a retweet, or a reply to another tweet. @@ -1330,11 +1330,11 @@ pub trait Summary { A `Summary` trait that consists of the behavior provided by a `summarize` method Here, we declare a trait using the `trait` keyword and then the trait’s name, -which is `Summary` in this case. We’ve also declared the trait as `pub` so that +which is `Summary` in this case. We also declare the trait as `pub` so that crates depending on this crate can make use of this trait too, as we’ll see in a few examples. Inside the curly brackets, we declare the method signatures that describe the behaviors of the types that implement this trait, which in -this case is `fn summarize(&self) -> String`. +this case is `fn` `summarize(&self) -> String`. After the method signature, instead of providing an implementation within curly brackets, we use a semicolon. Each type implementing this trait must provide @@ -1343,7 +1343,7 @@ that any type that has the `Summary` trait will have the method `summarize` defined with this signature exactly. A trait can have multiple methods in its body: the method signatures are listed -one per line and each line ends in a semicolon. +one per line, and each line ends in a semicolon. ### Implementing a Trait on a Type @@ -1752,7 +1752,7 @@ After we define `summarize_author`, we can call `summarize` on instances of the `Tweet` struct, and the default implementation of `summarize` will call the definition of `summarize_author` that we’ve provided. Because we’ve implemented `summarize_author`, the `Summary` trait has given us the behavior of the -`summarize` method without requiring us to write any more code. Here's what +`summarize` method without requiring us to write any more code. Here’s what that looks like: ``` @@ -2249,7 +2249,7 @@ references are valid as long as we need them to be. One detail we didn’t discuss in “References and Borrowing” on page XX is that every reference in Rust has a *lifetime*, which is the scope for which that reference is valid. Most of the time, lifetimes are implicit and inferred, just -like most of the time, types are inferred. We only must annotate types when +like most of the time, types are inferred. We must annotate types only when multiple types are possible. In a similar way, we must annotate lifetimes when the lifetimes of references could be related in a few different ways. Rust requires us to annotate the relationships using generic lifetime parameters to @@ -2363,7 +2363,7 @@ error[E0597]: `x` does not live long enough | - borrow later used here ``` -The error message says that the variable `x` doesn’t “live long enough.” The +The error message says that the variable `x` “does not live long enough.” The reason is that `x` will be out of scope when the inner scope ends on line 7. But `r` is still valid for the outer scope; because its scope is larger, we say that it “lives longer.” If Rust allowed this code to work, `r` would be @@ -2426,7 +2426,7 @@ lifetimes and sees that `r` has a lifetime of `'a` but that it refers to memory with a lifetime of `'b`. The program is rejected because `'b` is shorter than `'a`: the subject of the reference doesn’t live as long as the reference. -Listing 10-18 fixes the code so it doesn’t have a dangling reference and +Listing 10-18 fixes the code so it doesn’t have a dangling reference and it compiles without any errors. ``` @@ -2885,13 +2885,13 @@ this because we annotated the lifetimes of the function parameters and return values using the same lifetime parameter `'a`. As humans, we can look at this code and see that `string1` is longer than -`string2` and therefore `result` will contain a reference to `string1`. Because -`string1` has not gone out of scope yet, a reference to `string1` will still be -valid for the `println!` statement. However, the compiler can’t see that the -reference is valid in this case. We’ve told Rust that the lifetime of the -reference returned by the `longest` function is the same as the smaller of the -lifetimes of the references passed in. Therefore, the borrow checker disallows -the code in Listing 10-23 as possibly having an invalid reference. +`string2`, and therefore, `result` will contain a reference to `string1`. +Because `string1` has not gone out of scope yet, a reference to `string1` will +still be valid for the `println!` statement. However, the compiler can’t see +that the reference is valid in this case. We’ve told Rust that the lifetime of +the reference returned by the `longest` function is the same as the smaller of +the lifetimes of the references passed in. Therefore, the borrow checker +disallows the code in Listing 10-23 as possibly having an invalid reference. Try designing more experiments that vary the values and lifetimes of the references passed in to the `longest` function and how the returned reference diff --git a/nostarch/chapter11.md b/nostarch/chapter11.md index 5a31c31cc..6556dfdb8 100644 --- a/nostarch/chapter11.md +++ b/nostarch/chapter11.md @@ -1320,7 +1320,9 @@ inside the function doesn’t panic. Listing 11-8 shows a test that checks that the error conditions of `Guess::new` happen when we expect them to. -Filename: src/lib.rs +``` +// src/lib.rs +``` ``` pub struct Guess { @@ -1351,7 +1353,19 @@ impl Guess { ``` ``` - panic!("Guess value must be between 1 and 100, got {value}."); + panic!( +``` + +``` + "Guess value must be between 1 and 100, got {}.", +``` + +``` + value +``` + +``` + ); ``` ``` @@ -1447,6 +1461,10 @@ filtered out; finished in 0.00s Looks good! Now let’s introduce a bug in our code by removing the condition that the `new` function will panic if the value is greater than 100: +``` +// src/lib.rs +``` + ``` --snip-- ``` @@ -1468,7 +1486,19 @@ impl Guess { ``` ``` - panic!("Guess value must be between 1 and 100, got {value}."); + panic!( +``` + +``` + "Guess value must be between 1 and 100, got {}.", +``` + +``` + value +``` + +``` + ); ``` ``` @@ -1558,7 +1588,9 @@ consider the modified code for `Guess` in Listing 11-9 where the `new` function panics with different messages depending on whether the value is too small or too large. -Filename: src/lib.rs +``` +// src/lib.rs +``` ``` --snip-- @@ -1585,7 +1617,11 @@ impl Guess { ``` ``` - "Guess value must be greater than or equal to 1, got {value}." + "Guess value must be greater than or equal to 1, got {}.", +``` + +``` + value ``` ``` @@ -1601,7 +1637,11 @@ impl Guess { ``` ``` - "Guess value must be less than or equal to 100, got {value}." + "Guess value must be less than or equal to 100, got {}.", +``` + +``` + value ``` ``` @@ -1687,6 +1727,14 @@ To see what happens when a `should_panic` test with an `expected` message fails, let’s again introduce a bug into our code by swapping the bodies of the `if value < 1` and the `else if value > 100` blocks: +``` +// src/lib.rs +``` + +``` +--snip-- +``` + ``` if value < 1 { ``` @@ -1696,7 +1744,11 @@ if value < 1 { ``` ``` - "Guess value must be less than or equal to 100, got {value}." + "Guess value must be less than or equal to 100, got {}.", +``` + +``` + value ``` ``` @@ -1712,7 +1764,11 @@ if value < 1 { ``` ``` - "Guess value must be greater than or equal to 1, got {value}." + "Guess value must be greater than or equal to 1, got {}.", +``` + +``` + value ``` ``` @@ -1723,6 +1779,10 @@ if value < 1 { } ``` +``` +--snip-- +``` + This time when we run the `should_panic` test, it will fail: ``` @@ -1813,6 +1873,8 @@ Our tests so far all panic when they fail. We can also write tests that use `Result`! Here’s the test from Listing 11-1, rewritten to use `Result` and return an `Err` instead of panicking: +Filename: src/lib.rs + ``` #[cfg(test)] ``` @@ -2534,8 +2596,8 @@ fn expensive_test() { } ``` -After `#[test]` we add the `#[ignore]` line to the test we want to exclude. Now -when we run our tests, `it_works` runs, but `expensive_test` doesn’t: +After `#[test]`, we add the `#[ignore]` line to the test we want to exclude. +Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t: ``` $ cargo test @@ -3060,9 +3122,9 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` -This command runs only the tests in the *tests/integration_test.rs* file. -#### Submodules in Integration Tests +Unmatched: BodyContinued + #### Submodules in Integration Tests As you add more integration tests, you might want to make more files in the *tests* directory to help organize them; for example, you can group the test @@ -3304,7 +3366,7 @@ fn it_adds_two() { ``` Note that the `mod common;` declaration is the same as the module declaration -we demonstrated in Listing 7-21. Then in the test function, we can call the +we demonstrated in Listing 7-21. Then, in the test function, we can call the `common::setup()` function. #### Integration Tests for Binary Crates diff --git a/nostarch/chapter12.md b/nostarch/chapter12.md index a125799e6..9e5d5cebd 100644 --- a/nostarch/chapter12.md +++ b/nostarch/chapter12.md @@ -37,7 +37,7 @@ 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) +* Organizing code (Chapter 7) * Using vectors and strings (Chapter 8) * Handling errors (Chapter 9) * Using traits and lifetimes where appropriate (Chapter 10) @@ -90,7 +90,7 @@ collection, such as a vector, that contains all the elements the iterator produces. The code in Listing 12-1 allows your `minigrep` program to read any command -line arguments passed to it and then collect the values into a vector. +line arguments passed to it, and then collect the values into a vector. Filename: src/main.rs @@ -269,7 +269,7 @@ fn main() { Creating variables to hold the query argument and file path argument As we saw when we printed the vector, the program’s name takes up the first -value in the vector at `args[0]`, so we’re starting arguments at index `1`. The +value in the vector at `args[0]`, so we’re starting arguments at index 1. The first argument `minigrep` takes is the string we’re searching for, so we put a reference to the first argument in the variable `query`. The second argument will be the file path, so we put a reference to the second argument in the @@ -993,7 +993,7 @@ 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!` +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 @@ -1108,7 +1108,7 @@ impl Config { Returning a `Result` from `Config::build` Our `build` function returns a `Result` with a `Config` instance in the success -case and a `&'static str` in the error case. Our error values will always be +case and an `&'static str` in the error case. Our error values will always be string literals that have the `'static` lifetime. We’ve made two changes in the body of the function: instead of calling `panic!` @@ -1500,7 +1500,7 @@ both cases: we print the error and exit. ### Splitting Code into a Library Crate Our `minigrep` project is looking good so far! Now we’ll split the -*src/**main.rs* file and put some code into the *src/**lib.rs* file. That way +*src/**main.rs* file and put some code into the *src/**lib.rs* file. That way, we can test the code and have a *src/**main.rs* file with fewer responsibilities. @@ -1554,7 +1554,15 @@ impl Config { ``` ``` - pub fn build(args: &[String]) -> Result { + pub fn build( +``` + +``` + args: &[String], +``` + +``` + ) -> Result { ``` ``` @@ -1784,7 +1792,19 @@ fast, productive."`. Filename: src/lib.rs ``` -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search<'a>( +``` + +``` + query: &str, +``` + +``` + contents: &'a str, +``` + +``` +) -> Vec<&'a str> { ``` ``` @@ -1819,7 +1839,7 @@ error[E0106]: missing lifetime specifier ``` ``` - --> src/lib.rs:28:51 + --> src/lib.rs:31:10 ``` ``` @@ -1827,15 +1847,27 @@ error[E0106]: missing lifetime specifier ``` ``` -28 | pub fn search(query: &str, contents: &str) -> Vec<&str> { +29 | query: &str, ``` ``` - | ---- ---- ^ expected named + | ---- ``` ``` -lifetime parameter +30 | contents: &str, +``` + +``` + | ---- +``` + +``` +31 | ) -> Vec<&str> { +``` + +``` + | ^ expected named lifetime parameter ``` ``` @@ -1843,15 +1875,11 @@ lifetime parameter ``` ``` - = help: this function's return type contains a borrowed value, + = help: this function's return type contains a borrowed value, but the ``` ``` -but the signature does not say whether it is borrowed from `query` or -``` - -``` -`contents` +signature does not say whether it is borrowed from `query` or `contents` ``` ``` @@ -1863,11 +1891,23 @@ help: consider introducing a named lifetime parameter ``` ``` -28 | pub fn search<'a>(query: &'a str, contents: &'a str) -> Vec<&'a str> { +28 ~ pub fn search<'a>( ``` ``` - | ++++ ++ ++ ++ +29 ~ query: &'a str, +``` + +``` +30 ~ contents: &'a str, +``` + +``` +31 ~ ) -> Vec<&'a str> { +``` + +``` + | ``` Rust can’t possibly know which of the two arguments we need, so we need to tell @@ -1928,7 +1968,7 @@ failures: ``` ``` -thread 'main' panicked at 'assertion failed: `(left == right)` +thread 'tests::one_result' panicked at 'assertion failed: `(left == right)` ``` ``` @@ -1936,7 +1976,7 @@ thread 'main' panicked at 'assertion failed: `(left == right)` ``` ``` - right: `[]`', src/lib.rs:44:9 + right: `[]`', src/lib.rs:47:9 ``` ``` @@ -1991,9 +2031,9 @@ that and implement `search`, our program needs to follow these steps: 1. If it does, add it to the list of values we’re returning. 1. If it doesn’t, do nothing. 1. Return the list of results that match. -Let’s work through each step, starting with iterating through lines. -#### Iterating Through Lines with the lines Method +Unmatched: BodyContinued + #### Iterating Through Lines with the lines Method Rust has a helpful method to handle line-by-line iteration of strings, conveniently named `lines`, that works as shown in Listing 12-17. Note that @@ -2002,7 +2042,19 @@ this won’t compile yet. Filename: src/lib.rs ``` -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search<'a>( +``` + +``` + query: &str, +``` + +``` + contents: &'a str, +``` + +``` +) -> Vec<&'a str> { ``` ``` @@ -2038,7 +2090,19 @@ Listing 12-18. Note that this still won’t compile yet. Filename: src/lib.rs ``` -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search<'a>( +``` + +``` + query: &str, +``` + +``` + contents: &'a str, +``` + +``` +) -> Vec<&'a str> { ``` ``` @@ -2081,7 +2145,19 @@ we return the vector, as shown in Listing 12-19. Filename: src/lib.rs ``` -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search<'a>( +``` + +``` + query: &str, +``` + +``` + contents: &'a str, +``` + +``` +) -> Vec<&'a str> { ``` ``` @@ -2702,7 +2778,15 @@ impl Config { ``` ``` - pub fn build(args: &[String]) -> Result { + pub fn build( +``` + +``` + args: &[String] +``` + +``` + ) -> Result { ``` ``` @@ -2887,7 +2971,7 @@ to use something else to print to standard error. ### Checking Where Errors Are Written -First, let’s observe how the content printed by `minigrep` is currently being +First let’s observe how the content printed by `minigrep` is currently being written to standard output, including any error messages we want to write to standard error instead. We’ll do that by redirecting the standard output stream to a file while intentionally causing an error. We won’t redirect the standard diff --git a/nostarch/chapter13.md b/nostarch/chapter13.md index f1bef3dd1..c2d9a9580 100644 --- a/nostarch/chapter13.md +++ b/nostarch/chapter13.md @@ -724,14 +724,14 @@ can specify what kinds of closures they can use. Closures will automatically implement one, two, or all three of these `Fn` traits, in an additive fashion, depending on how the closure’s body handles the values: -1. `FnOnce` applies to closures that can be called once. All closures implement +* `FnOnce` applies to closures that can be called once. All closures implement at least this trait because all closures can be called. A closure that moves captured values out of its body will only implement `FnOnce` and none of the other `Fn` traits because it can only be called once. -1. `FnMut` applies to closures that don’t move captured values out of their +* `FnMut` applies to closures that don’t move captured values out of their body, but that might mutate the captured values. These closures can be called more than once. -1. `Fn` applies to closures that don’t move captured values out of their body +* `Fn` applies to closures that don’t move captured values out of their body and that don’t mutate captured values, as well as closures that capture nothing from their environment. These closures can be called more than once without mutating their environment, which is important in cases such as calling a @@ -795,7 +795,7 @@ the closure we provide when calling `unwrap_or_else`. The trait bound specified on the generic type `F` is `FnOnce() -> T`, which means `F` must be able to be called once, take no arguments, and return a `T`. Using `FnOnce` in the trait bound expresses the constraint that -`unwrap_or_else` is only going to call `f` at most one time. In the body of +`unwrap_or_else` is only going to call `f` one time, at most. In the body of `unwrap_or_else`, we can see that if the `Option` is `Some`, `f` won’t be called. If the `Option` is `None`, `f` will be called once. Because all closures implement `FnOnce`, `unwrap_or_else` accepts the largest variety of @@ -1298,8 +1298,8 @@ method. In other words, the `Item` type will be the type returned from the iterator. The `Iterator` trait only requires implementors to define one method: the -`next` method, which returns one item of the iterator at a time wrapped in -`Some` and, when iteration is over, returns `None`. +`next` method, which returns one item of the iterator at a time, wrapped in +`Some`, and, when iteration is over, returns `None`. We can call the `next` method on iterators directly; Listing 13-12 demonstrates what values are returned from repeated calls to `next` on the iterator created @@ -2147,7 +2147,19 @@ project, which is reproduced here in Listing 13-21 as it was in Listing 12-19. Filename: src/lib.rs ``` -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search<'a>( +``` + +``` + query: &str, +``` + +``` + contents: &'a str, +``` + +``` +) -> Vec<&'a str> { ``` ``` @@ -2202,7 +2214,19 @@ concurrent access to the `results` vector. Listing 13-22 shows this change. Filename: src/lib.rs ``` -pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> { +pub fn search<'a>( +``` + +``` + query: &str, +``` + +``` + contents: &'a str, +``` + +``` +) -> Vec<&'a str> { ``` ``` diff --git a/nostarch/chapter14.md b/nostarch/chapter14.md index 23ea766bf..76fe2bf71 100644 --- a/nostarch/chapter14.md +++ b/nostarch/chapter14.md @@ -29,7 +29,7 @@ various options for compiling code. Each profile is configured independently of the others. Cargo has two main profiles: the `dev` profile Cargo uses when you run `cargo -build` and the `release` profile Cargo uses when you run `cargo build +build`, and the `release` profile Cargo uses when you run `cargo build --release`. The `dev` profile is defined with good defaults for development, and the `release` profile has good defaults for release builds. @@ -276,7 +276,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s ``` -Now if we change either the function or the example so the `assert_eq!` in the +Now, if we change either the function or the example so the `assert_eq!` in the example panics and run `cargo test` again, we’ll see that the doc tests catch that the example and the code are out of sync with each other! @@ -350,19 +350,19 @@ are and might have difficulty finding the pieces they want to use if your crate has a large module hierarchy. In Chapter 7, we covered how to make items public using the `pub` keyword, and -bring items into a scope with the `use` keyword. However, the structure that -makes sense to you while you’re developing a crate might not be very convenient -for your users. You might want to organize your structs in a hierarchy -containing multiple levels, but then people who want to use a type you’ve -defined deep in the hierarchy might have trouble finding out that type exists. -They might also be annoyed at having to enter `use` -`my_crate::some_module::another_module::UsefulType;` rather than `use` -`my_crate::UsefulType;`. +how to bring items into a scope with the `use` keyword. However, the structure +that makes sense to you while you’re developing a crate might not be very +convenient for your users. You might want to organize your structs in a +hierarchy containing multiple levels, but then people who want to use a type +you’ve defined deep in the hierarchy might have trouble finding out that type +exists. They might also be annoyed at having to enter `use` +`my_crate``::`some_module`::`another_module`::`UsefulType`;` rather than `use` +`my_crate``::`UsefulType`;`. The good news is that if the structure *isn’t* convenient for others to use from another library, you don’t have to rearrange your internal organization: instead, you can re-export items to make a public structure that’s different -from your private structure by using `pub use`. Re-exporting takes a public +from your private structure by using `pub use`. *Re-exporting* takes a public item in one location and makes it public in another location, as if it were defined in the other location instead. @@ -920,17 +920,17 @@ anyone can easily add your crate as a dependency of their project. When you’ve made changes to your crate and are ready to release a new version, you change the `version` value specified in your *Cargo.toml* file and republish. Use the Semantic Versioning rules at *http://semver.org* to decide -what an appropriate next version number is based on the kinds of changes you’ve -made. Then run `cargo publish` to upload the new version. +what an appropriate next version number is, based on the kinds of changes +you’ve made. Then run `cargo publish` to upload the new version. ### Deprecating Versions from Crates.io with cargo yank Although you can’t remove previous versions of a crate, you can prevent any future projects from adding them as a new dependency. This is useful when a crate version is broken for one reason or another. In such situations, Cargo -supports *yanking* a crate version. +supports yanking a crate version. -Yanking a version prevents new projects from depending on that version while +*Yanking* a version prevents new projects from depending on that version while allowing all existing projects that depend on it to continue. Essentially, a yank means that all projects with a *Cargo.lock* will not break, and any future *Cargo.lock* files generated will not use the yanked version. @@ -1651,8 +1651,8 @@ locally. This isn’t intended to replace system packages; it’s meant to be a convenient way for Rust developers to install tools that others have shared on *https://crates.io*. Note that you can only install packages that have binary targets. A *binary target* is the runnable program that is created if the crate -has an *src/main.rs* file or another file specified as a binary, as opposed to -a library target that isn’t runnable on its own but is suitable for including +has a *src/main.rs* file or another file specified as a binary, as opposed to a +library target that isn’t runnable on its own but is suitable for including within other programs. Usually, crates have information in the *README* file about whether a crate is a library, has a binary target, or both. diff --git a/nostarch/docx/chapter01.docx b/nostarch/docx/chapter01.docx index f3bccda5b..a0f6959df 100644 Binary files a/nostarch/docx/chapter01.docx and b/nostarch/docx/chapter01.docx differ diff --git a/nostarch/docx/chapter03.docx b/nostarch/docx/chapter03.docx index 0fec2184f..228ec53db 100644 Binary files a/nostarch/docx/chapter03.docx and b/nostarch/docx/chapter03.docx differ diff --git a/nostarch/docx/chapter04.docx b/nostarch/docx/chapter04.docx index ff520c30e..f609cca20 100644 Binary files a/nostarch/docx/chapter04.docx and b/nostarch/docx/chapter04.docx differ diff --git a/nostarch/docx/chapter05.docx b/nostarch/docx/chapter05.docx index 05d123801..16d68d10a 100644 Binary files a/nostarch/docx/chapter05.docx and b/nostarch/docx/chapter05.docx differ diff --git a/nostarch/docx/chapter06.docx b/nostarch/docx/chapter06.docx index ea8836633..7680ec924 100644 Binary files a/nostarch/docx/chapter06.docx and b/nostarch/docx/chapter06.docx differ diff --git a/nostarch/docx/chapter07.docx b/nostarch/docx/chapter07.docx index 5e618453b..e2955957a 100644 Binary files a/nostarch/docx/chapter07.docx and b/nostarch/docx/chapter07.docx differ diff --git a/nostarch/docx/chapter08.docx b/nostarch/docx/chapter08.docx index 80edf74a1..761b2e28e 100644 Binary files a/nostarch/docx/chapter08.docx and b/nostarch/docx/chapter08.docx differ diff --git a/nostarch/docx/chapter09.docx b/nostarch/docx/chapter09.docx index 6571052ed..e516fe1b9 100644 Binary files a/nostarch/docx/chapter09.docx and b/nostarch/docx/chapter09.docx differ diff --git a/nostarch/docx/chapter10.docx b/nostarch/docx/chapter10.docx index b3371eb29..09fa0acde 100644 Binary files a/nostarch/docx/chapter10.docx and b/nostarch/docx/chapter10.docx differ diff --git a/nostarch/docx/chapter11.docx b/nostarch/docx/chapter11.docx index efb8db912..a34739235 100644 Binary files a/nostarch/docx/chapter11.docx and b/nostarch/docx/chapter11.docx differ diff --git a/nostarch/docx/chapter12.docx b/nostarch/docx/chapter12.docx index ac3117afe..eba55b866 100644 Binary files a/nostarch/docx/chapter12.docx and b/nostarch/docx/chapter12.docx differ diff --git a/nostarch/docx/chapter13.docx b/nostarch/docx/chapter13.docx index cd3363d39..39dae6b33 100644 Binary files a/nostarch/docx/chapter13.docx and b/nostarch/docx/chapter13.docx differ diff --git a/nostarch/docx/chapter14.docx b/nostarch/docx/chapter14.docx index 45fa81c83..e5f8f6d70 100644 Binary files a/nostarch/docx/chapter14.docx and b/nostarch/docx/chapter14.docx differ diff --git a/nostarch/docx/frontmatter.docx b/nostarch/docx/frontmatter.docx index 869a63f4b..65d41f251 100644 Binary files a/nostarch/docx/frontmatter.docx and b/nostarch/docx/frontmatter.docx differ diff --git a/nostarch/frontmatter.md b/nostarch/frontmatter.md index e23cc9fb9..527b2bca8 100644 --- a/nostarch/frontmatter.md +++ b/nostarch/frontmatter.md @@ -184,10 +184,10 @@ Goulding, and her daughter, Vivian. ## Preface This version of the text assumes you’re using Rust 1.62.0 (released 2022-06-30) -or later with `edition="2021"` in *Cargo.toml* of all projects to configure -them to use Rust 2021 edition idioms. See “Installation” on page XX for -instructions on installing or updating Rust, and see Appendix E for information -on editions. +or later with `edition="2021"` in the *Cargo.toml* file of all projects to +configure them to use Rust 2021 edition idioms. See “Installation” on page XX +for instructions on installing or updating Rust, and see Appendix E for +information on editions. The 2021 edition of the Rust language includes a number of improvements that make Rust more ergonomic and that correct some inconsistencies. On top of a @@ -221,7 +221,7 @@ backward-compatibility guarantees at work! ## Introduction -Welcome to *The Rust Programming Language,* an introductory book about Rust. +Welcome to *The Rust Programming Language*, an introductory book about Rust. The Rust programming language helps you write faster, more reliable software. High-level ergonomics and low-level control are often at odds in programming language design; Rust challenges that conflict. Through balancing powerful