Re-review of earlier chapters

This commit is contained in:
Carol (Nichols || Goulding) 2022-08-24 09:12:29 -04:00 committed by Carol (Nichols || Goulding)
parent a27da72da7
commit 6a8e75d917
28 changed files with 445 additions and 222 deletions

View File

@ -135,7 +135,7 @@ $ echo $PATH
If thats all correct and Rust still isnt 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, youll 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 youre 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 wont 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* (*Toms* *Obvious,* *Minimal* *Language*) format,
This file is in the *TOML* (*Toms* *Obvious,* *Minimal* *Language*) format,
which is Cargos 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, well 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. Well
talk about the `edition` key in Appendix E.
your program: the name, the version, and the edition of Rust to use. Well 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 projects dependencies. In Rust, packages of code are referred to as

View File

@ -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). Rusts 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 thats easier to understand and verify, rather than setting this constant
to the value 10,800. See the Rust References 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 References 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. Rusts 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 its roughly the same speed as `f32` but is capable of
because on modern CPUs, its roughly the same speed as `f32` but is capable of
more precision. All floating-point types are signed.
Heres 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, youll 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`, youll 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 dont 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. Thats because Rust only executes the block for the first true
block. Thats because Rust only executes the block for the first `true`
condition, and once it finds one, it doesnt 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, well 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. Its possible to implement behavior
like this using a combination of `loop`, `if`, `else`, and `break`; you could
try that now in a program, if youd 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

View File

@ -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 computers 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`. Well 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`. Well 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 doesnt 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 wont 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, theres a design choice thats 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`. Well 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
Lets take a closer look at exactly whats 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 its a separate value from the `String`, theres 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 Rusts `..` 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 Rusts `..` 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");

View File

@ -829,8 +829,8 @@ Defining a `Rectangle` struct
Here, weve 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 weve 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`). Well 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 were 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 youre 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 youre 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
weve 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 weve 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 dont 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 structs
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, were choosing to make the `width` method return `true` if the value in
the instances `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 dont use parentheses, Rust knows we mean the field `width`.
the instances `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 dont 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 types 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 youre calling a method on the object directly and `->` if youre
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 doesnt 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.
> Heres how it works: when you call a method with `object.something()`, Rust
> Heres 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.
Lets 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 weve 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 weve 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`:
```

View File

@ -931,10 +931,10 @@ state value out of the `Coin` enum variant for `Quarter`.
### Matching with Option<T>
In the previous section, we wanted to get the inner `T` value out of the `Some`
case when using `Option<T>`; we can also handle `Option<T>` using `match` as we
did with the `Coin` enum! Instead of comparing coins, well compare the
variants of `Option<T>`, but the way that the `match` expression works remains
the same.
case when using `Option<T>`; we can also handle `Option<T>` using `match`, as
we did with the `Coin` enum! Instead of comparing coins, well compare the
variants of `Option<T>`, but the way the `match` expression works remains the
same.
Lets say we want to write a function that takes an `Option<i32>` and, if
theres a value inside, adds 1 to that value. If there isnt a value inside,
@ -1109,7 +1109,7 @@ shown
|
```
Rust knows that we didnt cover every possible case and even knows which
Rust knows that we didnt 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<T>`, 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 isnt run if the
value doesnt match the pattern.

View File

@ -258,7 +258,7 @@ Unmatched: BoxCode
## Defining Modules to Control Scope and Privacy
In this section, well 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. Well 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 youll make
based on your project, and depends on whether youre 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 youre 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`, wed
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`, wed
have two `Result` types in the same scope and Rust wouldnt know which one we
have two `Result` types in the same scope, and Rust wouldnt 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
compilers rules for which files to check for which modules code means the
compilers rules for which files to check for which modules code mean the
directories and files more closely match the module tree.

View File

@ -118,7 +118,7 @@ we dont need the `Vec<i32>` 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, weve 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 wont work. Instead, you can use a trait
object, which well cover in Chapter 17.
Now that weve 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<T>` 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 couldnt 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 wouldnt be able to print
its value on the last line. However, this code works as wed 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 were 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 cant add two `String`
function: we can only add a `&``str` to a `String`; we cant 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, its difficult to see whats going on. For more complicated string
combining, we can instead use the `format!` macro:
characters, its difficult to see whats 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<K, V>`
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. Well 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. Lets say
we want to check whether the key for the Yellow team has a value associated
with it. If it doesnt, we want to insert the value 50, and the same for the
with it. If it doesnt, 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

View File

@ -1,8 +1,3 @@
<!-- DO NOT EDIT THIS FILE.
This file is periodically generated from the content in the `/src/`
directory, so all fixes need to be made in `/src/`.
-->
[TOC]
@ -180,7 +175,7 @@ wrote. Thats 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 youre using. Lets 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 youll 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 doesnt 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 didnt 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<T, E>` values in your code.
For example, heres 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 were going to start b
doing a lot of it manually in order to explore error handling; at the end,
well show the shorter way. Lets look at the return type of the function
first: `Result<String, io::Error>` [1]. This means the function is returning a
value of the type `Result<T, E>` 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<T, E>`, 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<T>` is similar to its behavior when called on a `Result<T, E>`:
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,
wed 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 doesnt 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 its not a kind of
contract violation always indicates a caller-side bug, and its not a kind of
error you want the calling code to have to explicitly handle. In fact, theres
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 thats out of range versus when a user
types, for example, letters instead.
behavior when the user guesses a number thats 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

View File

@ -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, weve already
used generics in Chapter 6 with `Option<T>`, Chapter 8 with `Vec<T>` and
`HashMap<K, V>`, and Chapter 9 with `Result<T, E>`. In this chapter, youll
used generics in Chapter 6 with `Option<T>`, in Chapter 8 with `Vec<T>` and
`HashMap<K, V>`, and in Chapter 9 with `Result<T, E>`. In this chapter, youll
explore how to define your own types, functions, and methods with generics!
First well review how to extract a function to reduce code duplication. Well
@ -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, well 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 well use `T` because, by
convention, type parameter names in Rust are short, often just one letter, and
Rusts type-naming convention is CamelCase. Short for “type,” `T` is the
Rusts 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<T>`. Then when we specify 4.0 for `y`, which weve 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<T>`. Then when we specify `4.0` for `y`, which weve defined to have the
same type as `x`, well 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, lets 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 traits name,
which is `Summary` in this case. Weve 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 well 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 weve provided. Because weve 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. Heres what
that looks like:
```
@ -2249,7 +2249,7 @@ references are valid as long as we need them to be.
One detail we didnt 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` doesnt “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 doesnt live as long as the reference.
Listing 10-18 fixes the code so it doesnt have a dangling reference and
Listing 10-18 fixes the code so it doesnt 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 cant see that the
reference is valid in this case. Weve 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 cant see
that the reference is valid in this case. Weve 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

View File

@ -1320,7 +1320,9 @@ inside the function doesnt 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 lets 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, lets 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<T, E>`! Heres the test from Listing 11-1, rewritten to use `Result<T,
E>` 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` doesnt:
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` doesnt:
```
$ 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

View File

@ -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 youve 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 programs name takes up the first
value in the vector at `args[0]`, so were starting arguments at index `1`. The
value in the vector at `args[0]`, so were starting arguments at index 1. The
first argument `minigrep` takes is the string were 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, were 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`, lets 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.
Weve 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 well 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<Config, &'static str> {
pub fn build(
```
```
args: &[String],
```
```
) -> Result<Config, &'static str> {
```
```
@ -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 cant 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 were returning.
1. If it doesnt, do nothing.
1. Return the list of results that match.
Lets 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 wont 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 wont 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<Config, &'static str> {
pub fn build(
```
```
args: &[String]
```
```
) -> Result<Config, &'static str> {
```
```
@ -2887,7 +2971,7 @@ to use something else to print to standard error.
### Checking Where Errors Are Written
First, lets observe how the content printed by `minigrep` is currently being
First lets 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. Well do that by redirecting the standard output stream
to a file while intentionally causing an error. We wont redirect the standard

View File

@ -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 closures 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 dont move captured values out of their
* `FnMut` applies to closures that dont 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 dont move captured values out of their body
* `Fn` applies to closures that dont move captured values out of their body
and that dont 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` wont 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> {
```
```

View File

@ -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, well 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 youre 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 youve
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 youre 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
youve 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 *isnt* convenient for others to use
from another library, you dont have to rearrange your internal organization:
instead, you can re-export items to make a public structure thats 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 youve 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 youve
made. Then run `cargo publish` to upload the new version.
what an appropriate next version number is, based on the kinds of changes
youve made. Then run `cargo publish` to upload the new version.
### Deprecating Versions from Crates.io with cargo yank
Although you cant 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 isnt intended to replace system packages; its 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 isnt 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 isnt 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -184,10 +184,10 @@ Goulding, and her daughter, Vivian.
## Preface
This version of the text assumes youre 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