Regenerate everything

This commit is contained in:
Carol (Nichols || Goulding) 2022-09-13 12:54:09 -04:00 committed by Carol (Nichols || Goulding)
parent d57b3d4764
commit 786fbf17b4
24 changed files with 1648 additions and 9639 deletions

142
nostarch/appendix_a.md Normal file
View File

@ -0,0 +1,142 @@
<!-- 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]
## Appendix A: Keywords
The following lists contain keywords that are reserved for current or future
use by the Rust language. As such, they cannot be used as identifiers (except
as raw identifiers, as well discuss in “Raw Identifiers” on page XX).
*Identifiers* are names of functions, variables, parameters, struct fields,
modules, crates, constants, macros, static values, attributes, types, traits,
or lifetimes.
## Keywords Currently in Use
The following is a list of keywords currently in use, with their functionality
described.
* **`as` **: perform primitive casting, disambiguate the specific trait
containing an item, or rename items in `use` statements
* **`async` **: return a `Future` instead of blocking the current thread
* **`await` **: suspend execution until the result of a `Future` is ready
* **`break` **: exit a loop immediately
* **`const` **: define constant items or constant raw pointers
* **`continue` **: continue to the next loop iteration
* **`crate` **: in a module path, refers to the crate root
* **`dyn` **: dynamic dispatch to a trait object
* **`else` **: fallback for `if` and `if let` control flow constructs
* **`enum` **: define an enumeration
* **`extern` **: link an external function or variable
* **`false` **: Boolean false literal
* **`fn` **: define a function or the function pointer type
* **`for` **: loop over items from an iterator, implement a trait, or specify a
higher-ranked lifetime
* **`if` **: branch based on the result of a conditional expression
* **`impl` **: implement inherent or trait functionality
* **`in` **: part of `for` loop syntax
* **`let` **: bind a variable
* **`loop` **: loop unconditionally
* **`match` **: match a value to patterns
* **`mod` **: define a module
* **`move` **: make a closure take ownership of all its captures
* **`mut` **: denote mutability in references, raw pointers, or pattern bindings
* **`pub` **: denote public visibility in struct fields, `impl` blocks, or
modules
* **`ref` **: bind by reference
* **`return` **: return from function
* **`Self` **: a type alias for the type we are defining or implementing
* **`self` **: method subject or current module
* **`static` **: global variable or lifetime lasting the entire program
execution
* **`struct` **: define a structure
* **`super` **: parent module of the current module
* **`trait` **: define a trait
* **`true` **: Boolean true literal
* **`type` **: define a type alias or associated type
* **`union` **: define a union; is a keyword only when used in a union
declaration
* **`unsafe` **: denote unsafe code, functions, traits, or implementations
* **`use` **: bring symbols into scope
* **`where` **: denote clauses that constrain a type
* **`while` **: loop conditionally based on the result of an expression
## Keywords Reserved for Future Use
The following keywords do not yet have any functionality but are reserved by
Rust for potential future use:
* `abstract`
* `become`
* `box`
* `do`
* `final`
* `macro`
* `override`
* `priv`
* `try`
* `typeof`
* `unsized`
* `virtual`
* `yield`
## Raw Identifiers
*Raw identifiers* are the syntax that lets you use keywords where they wouldnt
normally be allowed. You use a raw identifier by prefixing a keyword with `r#`.
For example, `match` is a keyword. If you try to compile the following function
that uses `match` as its name:
Filename: src/main.rs
```
fn match(needle: &str, haystack: &str) -> bool {
haystack.contains(needle)
}
```
youll get this error:
```
error: expected identifier, found keyword `match`
--> src/main.rs:4:4
|
4 | fn match(needle: &str, haystack: &str) -> bool {
| ^^^^^ expected identifier, found keyword
```
The error shows that you cant use the keyword `match` as the function
identifier. To use `match` as a function name, you need to use the raw
identifier syntax, like this:
Filename: src/main.rs
```
fn r#match(needle: &str, haystack: &str) -> bool {
haystack.contains(needle)
}
fn main() {
assert!(r#match("foo", "foobar"));
}
```
This code will compile without any errors. Note the `r#` prefix on the function
name in its definition as well as where the function is called in `main`.
Raw identifiers allow you to use any word you choose as an identifier, even if
that word happens to be a reserved keyword. This gives us more freedom to
choose identifier names, as well as lets us integrate with programs written in
a language where these words arent keywords. In addition, raw identifiers
allow you to use libraries written in a different Rust edition than your crate
uses. For example, `try` isnt a keyword in the 2015 edition but is in the 2018
and 2021 editions. If you depend on a library that is written using the 2015
edition and has a `try` function, youll need to use the raw identifier syntax,
`r#try` in this case, to call that function from your 2021 edition code. See
Appendix E for more information on editions.

242
nostarch/appendix_b.md Normal file
View File

@ -0,0 +1,242 @@
<!-- 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]
## Appendix B: Operators and Symbols
This appendix contains a glossary of Rusts syntax, including operators and
other symbols that appear by themselves or in the context of paths, generics,
trait bounds, macros, attributes, comments, tuples, and brackets.
## Operators
Table B-1 contains the operators in Rust, an example of how the operator would
appear in context, a short explanation, and whether that operator is
overloadable. If an operator is overloadable, the relevant trait to use to
overload that operator is listed.
Table -1: Operators
| Operator | Example | Explanation | Overloadable? |
|---|---|---|---|
| `!` | `ident!(...)`, `ident!{...}`, `ident![...]` | Macro expansion | |
| `!` | `!expr` | Bitwise or logical complement | `Not` |
| `!=` | `expr != expr` | Nonequality comparison | `PartialEq` |
| `% | `expr % expr` | Arithmetic remainder | `Rem` |
| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemAssign` |
| `& | `&expr`, `&mut expr` | Borrow | |
| `&` | `&type`, `&mut type`, `&'a type`, `&'a mut type` | Borrowed pointer
type | |
| `&` | `expr & expr` | Bitwise AND | `BitAnd` |
| `&=` | `var &= expr` | Bitwise AND and assignment | `BitAndAssign` |
| `&&` | `expr && expr` | Short-circuiting logical AND | |
| `* | `expr * expr` | Arithmetic multiplication | `Mul` |
| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulAssign`
|
| `*` | `*expr` | Dereference | `Deref` |
| `*` | `*const type`, `*mut type | Raw pointer | |
| `+ | `trait + trait`, `'a + trait` | Compound type constraint | |
| `+ | `expr + expr` | Arithmetic addition | `Add` |
| `+=` | `var += expr` | Arithmetic addition and assignment | `AddAssign` |
| `,` | `expr, expr` | Argument and element separator | |
| `- | `- expr` | Arithmetic negation | `Neg` |
| `- | `expr - expr` | Arithmetic subtraction | `Sub` |
| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubAssign` |
| `-> | `fn(...) -> type`, `|…| -> type` | Function and closure return type | |
| `. | `expr.ident` | Member access | |
| `..` | `..`, `expr..`, `..expr`, `expr..expr` | Right-exclusive range literal
| `PartialOrd` |
| `..=` | `..=expr`, `expr..=expr` | Right-inclusive range literal |
`PartialOrd` |
| `..` | `..expr` | Struct literal update syntax | |
| `..` | `variant(x, ..)`, `struct_type { x, .. }` | “And the rest” pattern
binding | |
| `...` | `expr...expr` | (Deprecated, use `..=` instead) In a pattern:
inclusive range pattern | |
| `/ | `expr / expr` | Arithmetic division | `Div` |
| `/=` | `var /= expr` | Arithmetic division and assignment | `DivAssign` |
| `: | `pat: type`, `ident: type` | Constraints | |
| `:` | `ident: expr` | Struct field initializer | |
| `:` | `'a: loop {...}` | Loop label | |
| `; | `expr;` | Statement and item terminator | |
| `;` | `[...; len]` | Part of fixed-size array syntax | |
| `<<` | `expr << expr` | Left-shift | `Shl` |
| `<<=` | `var <<= expr` | Left-shift and assignment | `ShlAssign` |
| `<` | `expr < expr` | Less than comparison | `PartialOrd` |
| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |
| `=` | `var = expr`, `ident = type` | Assignment/equivalence | |
| `==` | `expr == expr` | Equality comparison | `PartialEq` |
| `=>` | `pat => expr` | Part of match arm syntax | |
| `>` | `expr > expr` | Greater than comparison | `PartialOrd` |
| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` |
| `>>` | `expr >> expr` | Right-shift | `Shr` |
| `>>=` | `var >>= expr` | Right-shift and assignment | `ShrAssign` |
| `@ | `ident @ pat` | Pattern binding | |
| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` |
| `^=` | `var ^= expr` | Bitwise exclusive OR and assignment | `BitXorAssign` |
| `| | `pat | pat` | Pattern alternatives | |
| `|` | `expr | expr` | Bitwise OR | `BitOr` |
| `|=` | `var |= expr` | Bitwise OR and assignment | `BitOrAssign` |
| `||` | `expr || expr` | Short-circuiting logical OR | |
| `? | `expr?` | Error propagation | |
## Non-operator Symbols
The following tables contain all symbols that dont function as operators; that
is, they dont behave like a function or method call.
Table B-2 shows symbols that appear on their own and are valid in a variety of
locations.
Table -2: Stand-Alone Syntax
| Symbol | Explanation |
|---|---|
| `'ident | Named lifetime or loop label |
| `...u8`, `...i32`, `...f64`, `...usize`, and so on | Numeric literal of
specific type |
| `"..." | String literal |
| `r"..."`, `r#"..."#`, `r##"..."##`, and so on | Raw string literal; escape
characters not processed |
| `b"..."` | Byte string literal; constructs an array of bytes instead of a
string |
| `br"..."`, `br#"..."#`, `br##"..."##`, and so on | Raw byte string literal;
combination of raw and byte string literal |
| `'...' | Character literal |
| `b'...' | ASCII byte literal |
| `|…| expr | Closure |
| `! | Always-empty bottom type for diverging functions |
| `_ | “Ignored” pattern binding; also used to make integer literals readable |
Table B-3 shows symbols that appear in the context of a path through the module
hierarchy to an item.
Table -3: Path-Related Syntax
| Symbol | Explanation |
|---|---|
| `ident::ident | Namespace path |
| `::path` | Path relative to the crate root (that is, an explicitly absolute
path) |
| `self::path` | Path relative to the current module (that is, an explicitly
relative path) |
| `super::path` | Path relative to the parent of the current module |
| `type::ident`, `<type as trait>::ident | Associated constants, functions, and
types |
| `<type>::...` | Associated item for a type that cannot be directly named (for
example, `<&T>::...`, `<[T]>::...`, and so on) |
| `trait::method(...)` | Disambiguating a method call by naming the trait that
defines it |
| `type::method(...)` | Disambiguating a method call by naming the type for
which its defined |
| `<type as trait>::method(...)` | Disambiguating a method call by naming the
trait and type |
Table B-4 shows symbols that appear in the context of using generic type
parameters.
Table -4: Generics
| Symbol | Explanation |
|---|---|
| `path<...>` | Specifies parameters to a generic type in a type (for example,
`Vec<u8>`) |
| `path::<...>, method::<...>` | Specifies parameters to a generic type,
function, or method in an expression; often referred to as turbofish (for
example, `"42".parse::<i32>()`) |
| `fn ident<...> ...` | Define generic function |
| `struct ident<...> ...` | Define generic structure |
| `enum ident<...> ...` | Define generic enumeration |
| `impl<...> ...` | Define generic implementation |
| `for<...> type` | Higher-ranked lifetime bounds |
| `type<ident=type>` | A generic type where one or more associated types have
specific assignments (for example, `Iterator<Item=T>`) |
Table B-5 shows symbols that appear in the context of constraining generic type
parameters with trait bounds.
Table -5: Trait Bound Constraints
| Symbol | Explanation |
|---|---|
| T: U` | Generic parameter `T` constrained to types that implement `U` |
| `T: 'a` | Generic type `T` must outlive lifetime `'a` (meaning the type
cannot transitively contain any references with lifetimes shorter than `'a`) |
| `T: 'static` | Generic type `T` contains no borrowed references other than
`'static` ones |
| `'b: 'a` | Generic lifetime `'b` must outlive lifetime `'a` |
| `T: ?Sized` | Allow generic type parameter to be a dynamically sized type |
| `'a + trait`, `trait + trait` | Compound type constraint |
Table B-6 shows symbols that appear in the context of calling or defining
macros and specifying attributes on an item.
Table -6: Macros and Attributes
| Symbol | Explanation |
|---|---|
| `#[meta]` | Outer attribute |
| `#![meta]` | Inner attribute |
| `$ident` | Macro substitution |
| `$ident:kind` | Macro capture |
| `$(…)…` | Macro repetition |
| `ident!(...)`, `ident!{...}`, `ident![...]` | Macro invocation |
Table B-7 shows symbols that create comments.
Table -7: Comments
| Symbol | Explanation |
|---|---|
| `//` | Line comment |
| `//!` | Inner line doc comment |
| `///` | Outer line doc comment |
| `/*...*/` | Block comment |
| `/*!...*/` | Inner block doc comment |
| `/**...*/` | Outer block doc comment |
Table B-8 shows symbols that appear in the context of using tuples.
Table -8: Tuples
| Symbol | Explanation |
|---|---|
| `() | Empty tuple (aka unit), both literal and type |
| `(expr)` | Parenthesized expression |
| `(expr,)` | Single-element tuple expression |
| `(type,)` | Single-element tuple type |
| `(expr, ...)` | Tuple expression |
| `(type, ...)` | Tuple type |
| `expr(expr, ...)` | Function call expression; also used to initialize tuple
`struct`s and tuple `enum` variants |
| `expr.0`, `expr.1`, and so on | Tuple indexing |
Table B-9 shows the contexts in which curly brackets are used.
Table -9: Curly Brackets
| Context | Explanation |
|---|---|
| `{...}` | Block expression |
| `Type {...}` | `struct` literal |
Table B-10 shows the contexts in which square brackets are used.
Table -10: Square Brackets
| Context | Explanation |
|---|---|
| `[...]` | Array literal |
| `[expr; len]` | Array literal containing `len` copies of `expr` |
| `[type; len]` | Array type containing `len` instances of `type` |
| `expr[expr]` | Collection indexing; overloadable (`Index`, `IndexMut`) |
| `expr[..]`, `expr[a..]`, `expr[..b]`, `expr[a..b]` | Collection indexing
pretending to be collection slicing, using `Range`, `RangeFrom`, `RangeTo`, or
`RangeFull` as the “index” |
Unmatched:

184
nostarch/appendix_c.md Normal file
View File

@ -0,0 +1,184 @@
<!-- 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]
## Appendix C: Derivable Traits
In various places in the book, weve discussed the `derive` attribute, which
you can apply to a struct or enum definition. The `derive` attribute generates
code that will implement a trait with its own default implementation on the
type youve annotated with the `derive` syntax.
In this appendix, we provide a reference of all the traits in the standard
library that you can use with `derive`. Each section covers:
* What operators and methods deriving this trait will enable
* What the implementation of the trait provided by `derive` does
* What implementing the trait signifies about the type
* The conditions in which youre allowed or not allowed to implement the trait
* Examples of operations that require the trait
If you want different behavior from that provided by the `derive` attribute,
consult the standard library documentation for each trait for details on how to
manually implement them.
The traits listed here are the only ones defined by the standard library that
can be implemented on your types using `derive`. Other traits defined in the
standard library dont have sensible default behavior, so its up to you to
implement them in the way that makes sense for what youre trying to accomplish.
An example of a trait that cant be derived is `Display`, which handles
formatting for end users. You should always consider the appropriate way to
display a type to an end user. What parts of the type should an end user be
allowed to see? What parts would they find relevant? What format of the data
would be most relevant to them? The Rust compiler doesnt have this insight, so
it cant provide appropriate default behavior for you.
The list of derivable traits provided in this appendix is not comprehensive:
libraries can implement `derive` for their own traits, making the list of
traits you can use `derive` with truly open ended. Implementing `derive`
involves using a procedural macro, which is covered in “Macros” on page XX.
## Debug for Programmer Output
The `Debug` trait enables debug formatting in format strings, which you
indicate by adding `:?` within `{}` placeholders.
The `Debug` trait allows you to print instances of a type for debugging
purposes, so you and other programmers using your type can inspect an instance
at a particular point in a programs execution.
The `Debug` trait is required, for example, in the use of the `assert_eq!`
macro. This macro prints the values of instances given as arguments if the
equality assertion fails so programmers can see why the two instances werent
equal.
## PartialEq and Eq for Equality Comparisons
The `PartialEq` trait allows you to compare instances of a type to check for
equality and enables use of the `==` and `!=` operators.
Deriving `PartialEq` implements the `eq` method. When `PartialEq` is derived on
structs, two instances are equal only if *all* fields are equal, and the
instances are not equal if any fields are not equal. When derived on enums,
each variant is equal to itself and not equal to the other variants.
The `PartialEq` trait is required, for example, with the use of the
`assert_eq!` macro, which needs to be able to compare two instances of a type
for equality.
The `Eq` trait has no methods. Its purpose is to signal that for every value of
the annotated type, the value is equal to itself. The `Eq` trait can only be
applied to types that also implement `PartialEq`, although not all types that
implement `PartialEq` can implement `Eq`. One example of this is floating-point
number types: the implementation of floating-point numbers states that two
instances of the not-a-number (`NaN`) value are not equal to each other.
An example of when `Eq` is required is for keys in a `HashMap<K, V>` so that
the `HashMap<K, V>` can tell whether two keys are the same.
## PartialOrd and Ord for Ordering Comparisons
The `PartialOrd` trait allows you to compare instances of a type for sorting
purposes. A type that implements `PartialOrd` can be used with the `<`, `>`,
`<=`, and `>=` operators. You can only apply the `PartialOrd` trait to types
that also implement `PartialEq`.
Deriving `PartialOrd` implements the `partial_cmp` method, which returns an
`Option<Ordering>` that will be `None` when the values given dont produce an
ordering. An example of a value that doesnt produce an ordering, even though
most values of that type can be compared, is the not-a-number (`NaN`) floating
point value. Calling `partial_cmp` with any floating-point number and the `NaN`
floating-point value will return `None`.
When derived on structs, `PartialOrd` compares two instances by comparing the
value in each field in the order in which the fields appear in the struct
definition. When derived on enums, variants of the enum declared earlier in the
enum definition are considered less than the variants listed later.
The `PartialOrd` trait is required, for example, for the `gen_range` method
from the `rand` crate that generates a random value in the range specified by a
range expression.
The `Ord` trait allows you to know that for any two values of the annotated
type, a valid ordering will exist. The `Ord` trait implements the `cmp` method,
which returns an `Ordering` rather than an `Option<Ordering>` because a valid
ordering will always be possible. You can only apply the `Ord` trait to types
that also implement `PartialOrd` and `Eq` (and `Eq` requires `PartialEq`). When
derived on structs and enums, `cmp` behaves the same way as the derived
implementation for `partial_cmp` does with `PartialOrd`.
An example of when `Ord` is required is when storing values in a `BTreeSet<T>`,
a data structure that stores data based on the sort order of the values.
## Clone and Copy for Duplicating Values
The `Clone` trait allows you to explicitly create a deep copy of a value, and
the duplication process might involve running arbitrary code and copying heap
data. See “Variables and Data Interacting with Clone” on page XX for more
information on `Clone`.
Deriving `Clone` implements the `clone` method, which when implemented for the
whole type, calls `clone` on each of the parts of the type. This means all the
fields or values in the type must also implement `Clone` to derive `Clone`.
An example of when `Clone` is required is when calling the `to_vec` method on a
slice. The slice doesnt own the type instances it contains, but the vector
returned from `to_vec` will need to own its instances, so `to_vec` calls
`clone` on each item. Thus the type stored in the slice must implement `Clone`.
The `Copy` trait allows you to duplicate a value by only copying bits stored on
the stack; no arbitrary code is necessary. See “Stack-Only Data: Copy” on page
XX for more information on `Copy`.
The `Copy` trait doesnt define any methods to prevent programmers from
overloading those methods and violating the assumption that no arbitrary code
is being run. That way, all programmers can assume that copying a value will be
very fast.
You can derive `Copy` on any type whose parts all implement `Copy`. A type that
implements `Copy` must also implement `Clone` because a type that implements
`Copy` has a trivial implementation of `Clone` that performs the same task as
`Copy`.
The `Copy` trait is rarely required; types that implement `Copy` have
optimizations available, meaning you dont have to call `clone`, which makes
the code more concise.
Everything possible with `Copy` you can also accomplish with `Clone`, but the
code might be slower or have to use `clone` in places.
## Hash for Mapping a Value to a Value of Fixed Size
The `Hash` trait allows you to take an instance of a type of arbitrary size and
map that instance to a value of fixed size using a hash function. Deriving
`Hash` implements the `hash` method. The derived implementation of the `hash`
method combines the result of calling `hash` on each of the parts of the type,
meaning all fields or values must also implement `Hash` to derive `Hash`.
An example of when `Hash` is required is in storing keys in a `HashMap<K, V>`
to store data efficiently.
## Default for Default Values
The `Default` trait allows you to create a default value for a type. Deriving
`Default` implements the `default` function. The derived implementation of the
`default` function calls the `default` function on each part of the type,
meaning all fields or values in the type must also implement `Default` to
derive `Default`.
The `Default::default` function is commonly used in combination with the struct
update syntax discussed in “Creating Instances from Other Instances with Struct
Update Syntax” on page XX. You can customize a few fields of a struct and then
set and use a default value for the rest of the fields by using
`..Default::default()`.
The `Default` trait is required when you use the method `unwrap_or_default` on
`Option<T>` instances, for example. If the `Option<T>` is `None`, the method
`unwrap_or_default` will return the result of `Default::default` for the type
`T` stored in the `Option<T>`.

175
nostarch/appendix_d.md Normal file
View File

@ -0,0 +1,175 @@
<!-- 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]
## Appendix D: Useful Development Tools
In this appendix, we talk about some useful development tools that the Rust
project provides. Well look at automatic formatting, quick ways to apply
warning fixes, a linter, and integrating with IDEs.
## Automatic Formatting with rustfmt
The `rustfmt` tool reformats your code according to the community code style.
Many collaborative projects use `rustfmt` to prevent arguments about which
style to use when writing Rust: everyone formats their code using the tool.
Rust installations include `rustfmt` by default, so you should already have the
programs `rustfmt` and `cargo-fmt` on your system. These two commands are
analagous to `rustc` and `cargo` in that `rustfmt` allows finer-grained control
and `cargo-fmt` understands conventions of a project that uses Cargo. To format
any Cargo project, enter the following:
```
$ cargo fmt
```
Running this command reformats all the Rust code in the current crate. This
should only change the code style, not the code semantics. For more information
on `rustfmt`, see its documentation at *https://github.com/rust-lang/rustfmt*.
## Fix Your Code with rustfix
The `rustfix` tool is included with Rust installations and can automatically
fix compiler warnings that have a clear way to correct the problem thats
likely what you want. Youve probably seen compiler warnings before. For
example, consider this code:
Filename: src/main.rs
```
fn do_something() {}
fn main() {
for i in 0..100 {
do_something();
}
}
```
Here, were calling the `do_something` function 100 times, but we never use the
variable `i` in the body of the `for` loop. Rust warns us about that:
```
$ cargo build
Compiling myprogram v0.1.0 (file:///projects/myprogram)
warning: unused variable: `i`
--> src/main.rs:4:9
|
4 | for i in 0..100 {
| ^ help: consider using `_i` instead
|
= note: #[warn(unused_variables)] on by default
Finished dev [unoptimized + debuginfo] target(s) in 0.50s
```
The warning suggests that we use `_i` as a name instead: the underscore
indicates that we intend for this variable to be unused. We can automatically
apply that suggestion using the `rustfix` tool by running the command `cargo
fix`:
```
$ cargo fix
Checking myprogram v0.1.0 (file:///projects/myprogram)
Fixing src/main.rs (1 fix)
Finished dev [unoptimized + debuginfo] target(s) in 0.59s
```
When we look at *src/main.rs* again, well see that `cargo fix` has changed the
code:
Filename: src/main.rs
```
fn do_something() {}
fn main() {
for _i in 0..100 {
do_something();
}
}
```
The `for` loop variable is now named `_i`, and the warning no longer appears.
You can also use the `cargo fix` command to transition your code between
different Rust editions. Editions are covered in Appendix E.
## More Lints with Clippy
The Clippy tool is a collection of lints to analyze your code so you can catch
common mistakes and improve your Rust code. Clippy is included with standard
Rust installations.
To run Clippys lints on any Cargo project, enter the following:
```
$ cargo clippy
```
For example, say you write a program that uses an approximation of a
mathematical constant, such as pi, as this program does:
Filename: src/main.rs
```
fn main() {
let x = 3.1415;
let r = 8.0;
println!("the area of the circle is {}", x * r * r);
}
```
Running `cargo clippy` on this project results in this error:
```
error: approximate value of `f{32, 64}::consts::PI` found
--> src/main.rs:2:13
|
2 | let x = 3.1415;
| ^^^^^^
|
= note: `#[deny(clippy::approx_constant)]` on by default
= help: consider using the constant directly
= help: for further information visit https://rust-lang.github.io/rust-
clippy/master/index.html#approx_constant
```
This error lets you know that Rust already has a more precise `PI` constant
defined, and that your program would be more correct if you used the constant
instead. You would then change your code to use the `PI` constant.
The following code doesnt result in any errors or warnings from Clippy:
Filename: src/main.rs
```
fn main() {
let x = std::f64::consts::PI;
let r = 8.0;
println!("the area of the circle is {}", x * r * r);
}
```
For more information on Clippy, see its documentation at
*https://github.com/rust-lang/rust-clippy**.*
## IDE Integration Using rust-analyzer
To help with IDE integration, the Rust community recommends using
`rust-analyzer`. This tool is a set of compiler-centric utilities that speak
Language Server Protocol, which is a specification for IDEs and programming
languages to communicate with each other. Different clients can use
`rust-analyzer`, such as the Rust analyzer plug-in for Visual Studio Code at
*https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer*.
Visit the `rust-analyzer` projects home page at
*https://rust-analyzer.github.io* for installation instructions, then install
the language server support in your particular IDE. Your IDE will gain
capabilities such as autocompletion, jump to definition, and inline errors

66
nostarch/appendix_e.md Normal file
View File

@ -0,0 +1,66 @@
<!-- 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]
## Appendix E: Editions
In Chapter 1, you saw that `cargo new` adds a bit of metadata to your
*Cargo.toml* file about an edition. This appendix talks about what that means!
The Rust language and compiler have a six-week release cycle, meaning users get
a constant stream of new features. Other programming languages release larger
changes less often; Rust releases smaller updates more frequently. After a
while, all of these tiny changes add up. But from release to release, it can be
difficult to look back and say, “Wow, between Rust 1.10 and Rust 1.31, Rust has
changed a lot!”
Every two or three years, the Rust team produces a new Rust *edition*. Each
edition brings together the features that have landed into a clear package with
fully updated documentation and tooling. New editions ship as part of the usual
six-week release process.
Editions serve different purposes for different people:
* For active Rust users, a new edition brings together incremental changes into
an easy-to-understand package.
* For non-users, a new edition signals that some major advancements have
landed, which might make Rust worth another look.
* For those developing Rust, a new edition provides a rallying point for the
project as a whole.
At the time of this writing, three Rust editions are available: Rust 2015, Rust
2018, and Rust 2021. This book is written using Rust 2021 edition idioms.
The `edition` key in *Cargo.toml* indicates which edition the compiler should
use for your code. If the key doesnt exist, Rust uses `2015` as the edition
value for backward compatibility reasons.
Each project can opt in to an edition other than the default 2015 edition.
Editions can contain incompatible changes, such as including a new keyword that
conflicts with identifiers in code. However, unless you opt in to those
changes, your code will continue to compile even as you upgrade the Rust
compiler version you use.
All Rust compiler versions support any edition that existed prior to that
compilers release, and they can link crates of any supported editions
together. Edition changes only affect the way the compiler initially parses
code. Therefore, if youre using Rust 2015 and one of your dependencies uses
Rust 2018, your project will compile and be able to use that dependency. The
opposite situation, where your project uses Rust 2018 and a dependency uses
Rust 2015, works as well.
To be clear: most features will be available on all editions. Developers using
any Rust edition will continue to see improvements as new stable releases are
made. However, in some cases, mainly when new keywords are added, some new
features might only be available in later editions. You will need to switch
editions if you want to take advantage of such features.
For more details, *The* *Edition Guide* at
*https://doc.rust-lang.org/stable/edition-guide* is a complete book about
editions that enumerates the differences between editions and explains how to
automatically upgrade your code to a new edition via `cargo fix`.

View File

@ -33,7 +33,6 @@ differ slightly between versions because Rust often improves error messages and
warnings. In other words, any newer, stable version of Rust you install using
these steps should work as expected with the content of this book.
> ### Command Line Notation
>
> In this chapter and throughout the book, well show some commands used in the
@ -222,7 +221,7 @@ fn main() {
}
```
A program that prints `Hello, world!`
Listing 1-1: A program that prints `Hello, world!`
Save the file and go back to your terminal window in the
*~/projects/hello_world* directory. On Linux or macOS, enter the following
@ -271,8 +270,8 @@ line as the function declaration, adding one space in between.
> Note: If you want to stick to a standard style across Rust projects, you can
use an automatic formatter tool called `rustfmt` to format your code in a
particular style (more on rustfmt in Appendix D). The Rust team has included
this tool with the standard Rust distribution, as rustc is, so it should
particular style (more on `rustfmt` in Appendix D). The Rust team has included
this tool with the standard Rust distribution, as `rustc` is, so it should
already be installed on your computer!
The body of the `main` function holds the following code:
@ -430,7 +429,7 @@ edition = "2021"
[dependencies]
```
Contents of *Cargo.toml* generated by `cargo new`
Listing 1-2: Contents of *Cargo.toml* generated by `cargo new`
This file is in the *TOML* (*Toms Obvious, Minimal Language*) format, which is
Cargos configuration format.

View File

@ -106,10 +106,7 @@ fn main() {
}
```
Code that gets a guess from the user and prints it
Prod: Please renumber the listing captions for this chapter—Listing 2-1,
Listing 2-2, etc.
Listing 2-1: Code that gets a guess from the user and prints it
This code contains a lot of information, so lets go over it line by line. To
obtain user input and then print the result as output, we need to bring the
@ -417,8 +414,8 @@ $ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 2.53s
```
The output from running `cargo build` after adding the `rand` crate as a
dependency
Listing 2-2: The output from running `cargo build` after adding the `rand`
crate as a dependency
You may see different version numbers (but they will all be compatible with the
code, thanks to SemVer!) and different lines (depending on the operating
@ -541,7 +538,7 @@ fn main() {
}
```
Adding code to generate a random number
Listing 2-3: Adding code to generate a random number
First we add the line `use rand::Rng;` [1]. The `Rng` trait defines methods
that random number generators implement, and this trait must be in scope for us
@ -623,7 +620,7 @@ fn main() {
}
```
Handling the possible return values of comparing two numbers
Listing 2-4: Handling the possible return values of comparing two numbers
First we add another `use` statement [1], bringing a type called
`std::cmp::Ordering` into scope from the standard library. The `Ordering` type
@ -748,8 +745,6 @@ with `secret_number` means Rust will infer that `secret_number` should be a
`u32` as well. So now the comparison will be between two values of the same
type!
Comp: Note that there is an emoji in the below paragraph
The `parse` method will only work on characters that can logically be converted
into numbers and so can easily cause errors. If, for example, the string
contained `A`👍`%`, there would be no way to convert that to a number. Because
@ -900,8 +895,8 @@ println!("You guessed: {guess}");
--snip--
```
Ignoring a non-number guess and asking for another guess instead of crashing
the program
Listing 2-5: Ignoring a non-number guess and asking for another guess instead
of crashing the program
We switch from an `expect` call to a `match` expression to move from crashing
on an error to handling the error. Remember that `parse` returns a `Result`
@ -995,7 +990,7 @@ fn main() {
}
```
Complete guessing game code
Listing 2-6: Complete guessing game code
At this point, youve successfully built the guessing game. Congratulations!

View File

@ -18,7 +18,6 @@ Specifically, youll learn about variables, basic types, functions, comments,
and control flow. These foundations will be in every Rust program, and learning
them early will give you a strong core to start from.
> ### Keywords
>
> The Rust language has a set of *keywords* that are reserved for use by the
@ -313,7 +312,7 @@ start with `i` instead of `u`) that takes up 32 bits of space. Table 3-1 shows
the built-in integer types in Rust. We can use any of these variants to declare
the type of an integer value.
Integer Types in Rust
Table 3-1: Integer Types in Rust
| Length | Signed | Unsigned |
|---|---|---|
@ -350,7 +349,7 @@ such as `57u8`, to designate the type. Number literals can also use `_` as a
visual separator to make the number easier to read, such as `1_000`, which will
have the same value as if you had specified `1000`.
Integer Literals in Rust
Table 3-2: Integer Literals in Rust
| Number literals | Example |
|---|---|
@ -365,7 +364,6 @@ defaults are generally good places to start: integer types default to `i32`.
The primary situation in which youd use `isize` or `usize` is when indexing
some sort of collection.
> ### Integer Overflow
>
> Lets say you have a variable of type `u8` that can hold values between 0 and
@ -852,9 +850,10 @@ understand. Other languages dont have the same distinctions, so lets look
what statements and expressions are and how their differences affect the bodies
of functions.
* Statements - are instructions that perform some action and do not return a
value.
* Expressions - evaluate to a resultant value. Lets look at some examples.
* **Statements **: are instructions that perform some action and do not return
a value.
* **Expressions **: evaluate to a resultant value. Lets look at some examples.
Weve actually already used statements and expressions. Creating a variable and
assigning a value to it with the `let` keyword is a statement. In Listing 3-1,
`let y = 6;` is a statement.
@ -867,7 +866,7 @@ fn main() {
}
```
A `main` function declaration containing one statement
Listing 3-1: A `main` function declaration containing one statement
Function definitions are also statements; the entire preceding example is a
statement in itself.
@ -1280,7 +1279,7 @@ fn main() {
}
```
Assigning the result of an `if` expression to a variable
Listing 3-2: Assigning the result of an `if` expression to a variable
The `number` variable will be bound to a value based on the outcome of the `if`
expression. Run this code to see what happens:
@ -1509,7 +1508,8 @@ fn main() {
}
```
Using a `while` loop to run code while a condition evaluates to `true`
Listing 3-3: Using a `while` loop to run code while a condition evaluates to
`true`
This construct eliminates a lot of nesting that would be necessary if you used
`loop`, `if`, `else`, and `break`, and its clearer. While a condition
@ -1536,7 +1536,7 @@ fn main() {
}
```
Looping through each element of a collection using a `while` loop
Listing 3-4: 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,
@ -1581,7 +1581,7 @@ fn main() {
}
```
Looping through each element of a collection using a `for` loop
Listing 3-5: Looping through each element of a collection using a `for` loop
When we run this code, well see the same output as in Listing 3-4. More
importantly, weve now increased the safety of the code and eliminated the

View File

@ -47,7 +47,7 @@ struct User {
}
```
A `User` struct definition
Listing 5-1: A `User` struct definition
To use a struct after weve defined it, we create an *instance* of that struct
by specifying concrete values for each of the fields. We create an instance by
@ -72,7 +72,7 @@ fn main() {
}
```
Creating an instance of the `User` struct
Listing 5-2: Creating an instance of the `User` struct
To get a specific value from a struct, we use dot notation. For example, to
access this users email address, we use `user1.email`. If the instance is
@ -95,7 +95,7 @@ fn main() {
}
```
Changing the value in the `email` field of a `User` instance
Listing 5-3: Changing the value in the `email` field of a `User` instance
Note that the entire instance must be mutable; Rust doesnt allow us to mark
only certain fields as mutable. As with any expression, we can construct a new
@ -117,8 +117,8 @@ fn build_user(email: String, username: String) -> User {
}
```
A `build_user` function that takes an email and username and returns a `User`
instance
Listing 5-4: A `build_user` function that takes an email and username and
returns a `User` instance
It makes sense to name the function parameters with the same name as the struct
fields, but having to repeat the `email` and `username` field names and
@ -143,8 +143,8 @@ fn build_user(email: String, username: String) -> User {
}
```
A `build_user` function that uses field init shorthand because the `username`
and `email` parameters have the same name as struct fields
Listing 5-5: A `build_user` function that uses field init shorthand because the
`username` and `email` parameters have the same name as struct fields
Here, were creating a new instance of the `User` struct, which has a field
named `email`. We want to set the `email` fields value to the value in the
@ -177,7 +177,7 @@ fn main() {
}
```
Creating a new `User` instance using one of the values from `user1`
Listing 5-6: Creating a new `User` instance using one of the values from `user1`
Using struct update syntax, we can achieve the same effect with less code, as
shown in Listing 5-7. The syntax `..` specifies that the remaining fields not
@ -197,8 +197,8 @@ fn main() {
}
```
Using struct update syntax to set a new `email` value for a `User` instance but
to use the rest of the values from `user1`
Listing 5-7: Using struct update syntax to set a new `email` value for a `User`
instance but to use the rest of the values from `user1`
The code in Listing 5-7 also creates an instance in `user2` that has a
different value for `email` but has the same values for the `username`,
@ -282,7 +282,6 @@ have a known result for testing purposes. We wouldnt need any data to
implement that behavior! Youll see in Chapter 10 how to define traits and
implement them on any type, including unit-like structs.
> ### Ownership of Struct Data
>
> In the `User` struct definition in Listing 5-1, we used the owned `String`
@ -381,8 +380,8 @@ fn area(width: u32, height: u32) -> u32 {
}
```
Calculating the area of a rectangle specified by separate width and height
variables
Listing 5-8: Calculating the area of a rectangle specified by separate width
and height variables
Now, run this program using `cargo run`:
@ -427,7 +426,7 @@ fn area(dimensions: (u32, u32)) -> u32 {
}
```
Specifying the width and height of the rectangle with a tuple
Listing 5-9: Specifying the width and height of the rectangle with a tuple
In one way, this program is better. Tuples let us add a bit of structure, and
were now passing just one argument [1]. But in another way, this version is
@ -472,7 +471,7 @@ fn main() {
}
```
Defining a `Rectangle` struct
Listing 5-10: 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
@ -520,7 +519,7 @@ fn main() {
}
```
Attempting to print a `Rectangle` instance
Listing 5-11: Attempting to print a `Rectangle` instance
When we compile this code, we get an error with this core message:
@ -590,8 +589,8 @@ fn main() {
}
```
Adding the attribute to derive the `Debug` trait and printing the `Rectangle`
instance using debug formatting
Listing 5-12: Adding the attribute to derive the `Debug` trait and printing the
`Rectangle` instance using debug formatting
Now when we run the program, we wont get any errors, and well see the
following output:
@ -728,7 +727,7 @@ fn main() {
}
```
Defining an `area` method on the `Rectangle` struct
Listing 5-13: Defining an `area` method on the `Rectangle` struct
To define the function within the context of `Rectangle`, we start an `impl`
(implementation) block for `Rectangle` [1]. Everything within this `impl` block
@ -811,7 +810,6 @@ to that field as part of the types public API. We will discuss what public an
private are and how to designate a field or method as public or private in
Chapter 7.
> ### Wheres the -> Operator?
>
> In C and C++, two different operators are used for calling methods: you use
@ -871,7 +869,7 @@ fn main() {
}
```
Using the as-yet-unwritten `can_hold` method
Listing 5-14: 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
@ -910,8 +908,8 @@ impl Rectangle {
}
```
Implementing the `can_hold` method on `Rectangle` that takes another
`Rectangle` instance as a parameter
Listing 5-15: Implementing the `can_hold` method on `Rectangle` that takes
another `Rectangle` instance as a parameter
When we run this code with the `main` function in Listing 5-14, well get our
desired output. Methods can take multiple parameters that we add to the
@ -977,7 +975,7 @@ impl Rectangle {
}
```
Rewriting Listing 5-15 using multiple `impl` blocks
Listing 5-16: Rewriting Listing 5-15 using multiple `impl` blocks
Theres no reason to separate these methods into multiple `impl` blocks here,
but this is valid syntax. Well see a case in which multiple `impl` blocks are

View File

@ -106,7 +106,8 @@ Listing 6-1.
};
```
Storing the data and `IpAddrKind` variant of an IP address using a `struct`
Listing 6-1: Storing the data and `IpAddrKind` variant of an IP address using a
`struct`
Here, weve defined a struct `IpAddr` [2] that has two fields: a `kind` field
[3] that is of type `IpAddrKind` (the enum we defined previously [1]) and an
@ -204,7 +205,8 @@ enum Message {
}
```
A `Message` enum whose variants each store different amounts and types of values
Listing 6-2: A `Message` enum whose variants each store different amounts and
types of values
This enum has four variants with different types:
@ -439,8 +441,8 @@ fn value_in_cents(coin: Coin) -> u8 {
}
```
An enum and a `match` expression that has the variants of the enum as its
patterns
Listing 6-3: An enum and a `match` expression that has the variants of the enum
as its patterns
Lets break down the `match` in the `value_in_cents` function. First we list
the `match` keyword followed by an expression, which in this case is the value
@ -514,7 +516,8 @@ enum Coin {
}
```
A `Coin` enum in which the `Quarter` variant also holds a `UsState` value
Listing 6-4: A `Coin` enum in which the `Quarter` variant also holds a
`UsState` value
Lets imagine that a friend is trying to collect all 50 state quarters. While
we sort our loose change by coin type, well also call out the name of the
@ -576,7 +579,7 @@ let six = plus_one(five); 3
let none = plus_one(None); 4
```
A function that uses a `match` expression on an `Option<i32>`
Listing 6-5: A function that uses a `match` expression on an `Option<i32>`
Lets examine the first execution of `plus_one` in more detail. When we call
`plus_one(five)` [3], the variable `x` in the body of `plus_one` will have the
@ -757,7 +760,8 @@ match config_max {
}
```
A `match` that only cares about executing code when the value is `Some`
Listing 6-6: A `match` that only cares about executing code when the value is
`Some`
If the value is `Some`, we print out the value in the `Some` variant by binding
the value to the variable `max` in the pattern. We dont want to do anything

View File

@ -263,7 +263,8 @@ mod front_of_house {
}
```
A `front_of_house` module containing other modules that then contain functions
Listing 7-1: A `front_of_house` module containing other modules that then
contain functions
We define a module with the `mod` keyword followed by the name of the module
(in this case, `front_of_house`). The body of the module then goes inside curly
@ -297,7 +298,7 @@ crate
└── take_payment
```
The module tree for the code in Listing 7-1
Listing 7-2: The module tree for the code in Listing 7-1
This tree shows how some of the modules nest inside other modules; for example,
`hosting` nests inside `front_of_house`. The tree also shows that some modules
@ -360,7 +361,8 @@ pub fn eat_at_restaurant() {
}
```
Calling the `add_to_waitlist` function using absolute and relative paths
Listing 7-3: Calling the `add_to_waitlist` function using absolute and relative
paths
The first time we call the `add_to_waitlist` function in `eat_at_restaurant`,
we use an absolute path. The `add_to_waitlist` function is defined in the same
@ -422,7 +424,7 @@ note: the module `hosting` is defined here
| ^^^^^^^^^^^
```
Compiler errors from building the code in Listing 7-3
Listing 7-4: Compiler errors from building the code in Listing 7-3
The error messages say that module `hosting` is private. In other words, we
have the correct paths for the `hosting` module and the `add_to_waitlist`
@ -464,7 +466,8 @@ mod front_of_house {
--snip--
```
Declaring the `hosting` module as `pub` to use it from `eat_at_restaurant`
Listing 7-5: Declaring the `hosting` module as `pub` to use it from
`eat_at_restaurant`
Unfortunately, the code in Listing 7-5 still results in compiler errors, as
shown in Listing 7-6.
@ -497,7 +500,7 @@ note: the function `add_to_waitlist` is defined here
| ^^^^^^^^^^^^^^^^^^^^
```
Compiler errors from building the code in Listing 7-5
Listing 7-6: Compiler errors from building the code in Listing 7-5
What happened? Adding the `pub` keyword in front of `mod hosting` makes the
module public. With this change, if we can access `front_of_house`, we can
@ -527,8 +530,8 @@ mod front_of_house {
--snip--
```
Adding the `pub` keyword to `mod hosting` and `fn add_to_waitlist` lets us call
the function from `eat_at_restaurant`.
Listing 7-7: Adding the `pub` keyword to `mod hosting` and `fn add_to_waitlist`
lets us call the function from `eat_at_restaurant`.
Now the code will compile! To see why adding the `pub` keyword lets us use
these paths in `add_to_waitlist` with respect to the privacy rules, lets look
@ -611,7 +614,7 @@ mod back_of_house {
}
```
Calling a function using a relative path starting with `super`
Listing 7-8: Calling a function using a relative path starting with `super`
The `fix_incorrect_order` function is in the `back_of_house` module, so we can
use `super` to go to the parent module of `back_of_house`, which in this case
@ -668,7 +671,7 @@ pub fn eat_at_restaurant() {
}
```
A struct with some public fields and some private fields
Listing 7-9: A struct with some public fields and some private fields
Because the `toast` field in the `back_of_house::Breakfast` struct is public,
in `eat_at_restaurant` we can write and read to the `toast` field using dot
@ -702,7 +705,7 @@ pub fn eat_at_restaurant() {
}
```
Designating an enum as public makes all its variants public.
Listing 7-10: Designating an enum as public makes all its variants public.
Because we made the `Appetizer` enum public, we can use the `Soup` and `Salad`
variants in `eat_at_restaurant`.
@ -747,7 +750,7 @@ pub fn eat_at_restaurant() {
}
```
Bringing a module into scope with `use`
Listing 7-11: Bringing a module into scope with `use`
Adding `use` and a path in a scope is similar to creating a symbolic link in
the filesystem. By adding `use crate::front_of_house::hosting` in the crate
@ -778,7 +781,7 @@ mod customer {
}
```
A `use` statement only applies in the scope its in.
Listing 7-12: A `use` statement only applies in the scope its in.
The compiler error shows that the shortcut no longer applies within the
`customer` module:
@ -827,8 +830,8 @@ pub fn eat_at_restaurant() {
}
```
Bringing the `add_to_waitlist` function into scope with `use`, which is
unidiomatic
Listing 7-13: Bringing the `add_to_waitlist` function into scope with `use`,
which is unidiomatic
Although both Listing 7-11 and Listing 7-13 accomplish the same task, Listing
7-11 is the idiomatic way to bring a function into scope with `use`. Bringing
@ -854,7 +857,7 @@ fn main() {
}
```
Bringing `HashMap` into scope in an idiomatic way
Listing 7-14: Bringing `HashMap` into scope in an idiomatic way
Theres no strong reason behind this idiom: its just the convention that has
emerged, and folks have gotten used to reading and writing Rust code this way.
@ -879,8 +882,8 @@ fn function2() -> io::Result<()> {
}
```
Bringing two types with the same name into the same scope requires using their
parent modules.
Listing 7-15: Bringing two types with the same name into the same scope
requires using their 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
@ -909,7 +912,7 @@ fn function2() -> IoResult<()> {
}
```
Renaming a type when its brought into scope with the `as` keyword
Listing 7-16: Renaming a type when its brought into scope with the `as` keyword
In the second `use` statement, we chose the new name `IoResult` for the
`std::io::Result` type, which wont conflict with the `Result` from `std::fmt`
@ -944,7 +947,8 @@ pub fn eat_at_restaurant() {
}
```
Making a name available for any code to use from a new scope with `pub use`
Listing 7-17: Making a name available for any code to use from a new scope with
`pub use`
Before this change, external code would have to call the `add_to_waitlist`
function by using the path
@ -1040,7 +1044,8 @@ use std::{cmp::Ordering, io};
--snip--
```
Specifying a nested path to bring multiple items with the same prefix into scope
Listing 7-18: Specifying a nested path to bring multiple items with the same
prefix into scope
In bigger programs, bringing many items into scope from the same crate or
module using nested paths can reduce the number of separate `use` statements
@ -1058,7 +1063,7 @@ use std::io;
use std::io::Write;
```
Two `use` statements where one is a subpath of the other
Listing 7-19: Two `use` statements where one is a subpath of the other
The common part of these two paths is `std::io`, and thats the complete first
path. To merge these two paths into one `use` statement, we can use `self` in
@ -1070,7 +1075,7 @@ Filename: src/lib.rs
use std::io::{self, Write};
```
Combining the paths in Listing 7-19 into one `use` statement
Listing 7-20: Combining the paths in Listing 7-19 into one `use` statement
This line brings `std::io` and `std::io::Write` into scope.
@ -1123,7 +1128,7 @@ pub fn eat_at_restaurant() {
}
```
Declaring the `front_of_house` module whose body will be in
Listing 7-21: Declaring the `front_of_house` module whose body will be in
*src/front_of_house.rs*
Next, place the code that was in the curly brackets into a new file named
@ -1139,7 +1144,8 @@ pub mod hosting {
}
```
Definitions inside the `front_of_house` module in *src/front_of_house.rs*
Listing 7-22: Definitions inside the `front_of_house` module in
*src/front_of_house.rs*
Note that you only need to load a file using a `mod` declaration *once* in your
module tree. Once the compiler knows the file is part of the project (and knows

View File

@ -47,7 +47,7 @@ Listing 8-1.
let v: Vec<i32> = Vec::new();
```
Creating a new, empty vector to hold values of type `i32`
Listing 8-1: Creating a new, empty vector to hold values of type `i32`
Note that we added a type annotation here. Because we arent inserting any
values into this vector, Rust doesnt know what kind of elements we intend to
@ -70,7 +70,7 @@ page XX.
let v = vec![1, 2, 3];
```
Creating a new vector containing values
Listing 8-2: Creating a new vector containing values
Because weve given initial `i32` values, Rust can infer that the type of `v`
is `Vec<i32>`, and the type annotation isnt necessary. Next, well look at how
@ -90,7 +90,7 @@ v.push(7);
v.push(8);
```
Using the `push` method to add values to a vector
Listing 8-3: Using the `push` method to add values to a vector
As with any variable, if we want to be able to change its value, we need to
make it mutable using the `mut` keyword, as discussed in Chapter 3. The numbers
@ -119,7 +119,8 @@ match third {
}
```
Using indexing syntax and using the `get` method to access an item in a vector
Listing 8-4: Using indexing syntax and using the `get` method to access an item
in a vector
Note a few details here. We use the index value of `2` to get the third element
[1] because vectors are indexed by number, starting at zero. Using `&` and `[]`
@ -140,8 +141,8 @@ let does_not_exist = &v[100];
let does_not_exist = v.get(100);
```
Attempting to access the element at index 100 in a vector containing five
elements
Listing 8-5: Attempting to access the element at index 100 in a vector
containing five elements
When we run this code, the first `[]` method will cause the program to panic
because it references a nonexistent element. This method is best used when you
@ -178,7 +179,8 @@ v.push(6);
println!("The first element is: {first}");
```
Attempting to add an element to a vector while holding a reference to an item
Listing 8-6: Attempting to add an element to a vector while holding a reference
to an item
Compiling this code will result in this error:
@ -224,8 +226,8 @@ for i in &v {
}
```
Printing each element in a vector by iterating over the elements using a `for`
loop
Listing 8-7: Printing each element in a vector by iterating over the elements
using a `for` loop
We can also iterate over mutable references to each element in a mutable vector
in order to make changes to all the elements. The `for` loop in Listing 8-8
@ -238,7 +240,7 @@ for i in &mut v {
}
```
Iterating over mutable references to elements in a vector
Listing 8-8: Iterating over mutable references to elements in a vector
To change the value that the mutable reference refers to, we have to use the
`*` dereference operator to get to the value in `i` before we can use the `+=`
@ -281,7 +283,7 @@ let row = vec![
];
```
Defining an `enum` to store values of different types in one vector
Listing 8-9: Defining an `enum` to store values of different types in one vector
Rust needs to know what types will be in the vector at compile time so it knows
exactly how much memory on the heap will be needed to store each element. We
@ -313,7 +315,7 @@ annotated in Listing 8-10.
} // <- v goes out of scope and is freed here
```
Showing where the vector and its elements are dropped
Listing 8-10: Showing where the vector and its elements are dropped
When the vector gets dropped, all of its contents are also dropped, meaning the
integers it holds will be cleaned up. The borrow checker ensures that any
@ -369,7 +371,7 @@ function to create an instance, shown in Listing 8-11.
let mut s = String::new();
```
Creating a new, empty `String`
Listing 8-11: Creating a new, empty `String`
This line creates a new, empty string called `s`, into which we can then load
data. Often, well have some initial data with which we want to start the
@ -386,7 +388,8 @@ let s = data.to_string();
let s = "initial contents".to_string();
```
Using the `to_string` method to create a `String` from a string literal
Listing 8-12: Using the `to_string` method to create a `String` from a string
literal
This code creates a string containing `initial contents`.
@ -398,7 +401,8 @@ that uses `to_string`.
let s = String::from("initial contents");
```
Using the `String::from` function to create a `String` from a string literal
Listing 8-13: Using the `String::from` function to create a `String` from a
string literal
Because strings are used for so many things, we can use many different generic
APIs for strings, providing us with a lot of options. Some of them can seem
@ -423,7 +427,7 @@ let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
```
Storing greetings in different languages in strings
Listing 8-14: Storing greetings in different languages in strings
All of these are valid `String` values.
@ -443,7 +447,7 @@ let mut s = String::from("foo");
s.push_str("bar");
```
Appending a string slice to a `String` using the `push_str` method
Listing 8-15: Appending a string slice to a `String` using the `push_str` method
After these two lines, `s` will contain `foobar`. The `push_str` method takes a
string slice because we dont necessarily want to take ownership of the
@ -457,7 +461,7 @@ s1.push_str(s2);
println!("s2 is {s2}");
```
Using a string slice after appending its contents to a `String`
Listing 8-16: Using a string slice after appending its contents to a `String`
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!
@ -471,7 +475,7 @@ let mut s = String::from("lo");
s.push('l');
```
Adding one character to a `String` value using `push`
Listing 8-17: Adding one character to a `String` value using `push`
As a result, `s` will contain `lol`.
@ -486,7 +490,8 @@ let s2 = String::from("world!");
let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used
```
Using the `+` operator to combine two `String` values into a new `String` value
Listing 8-18: Using the `+` operator to combine two `String` values into a new
`String` value
The string `s3` will contain `Hello, world!`. The reason `s1` is no longer
valid after the addition, and the reason we used a reference to `s2`, has to do
@ -567,7 +572,7 @@ let s1 = String::from("hello");
let h = s1[0];
```
Attempting to use indexing syntax with a `String`
Listing 8-19: Attempting to use indexing syntax with a `String`
This code will result in the following error:
@ -801,7 +806,7 @@ scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
```
Creating a new hash map and inserting some keys and values
Listing 8-20: Creating a new hash map and inserting some keys and values
Note that we need to first `use` the `HashMap` from the collections portion of
the standard library. Of our three common collections, this one is the least
@ -831,7 +836,7 @@ let team_name = String::from("Blue");
let score = scores.get(&team_name).copied().unwrap_or(0);
```
Accessing the score for the Blue team stored in the hash map
Listing 8-21: Accessing the score for the Blue team stored in the hash map
Here, `score` will have the value thats associated with the Blue team, and the
result will be `10`. The `get` method returns an `Option<&V>`; if theres no
@ -881,7 +886,8 @@ map.insert(field_name, field_value);
// using them and see what compiler error you get!
```
Showing that keys and values are owned by the hash map once theyre inserted
Listing 8-22: Showing that keys and values are owned by the hash map once
theyre inserted
We arent able to use the variables `field_name` and `field_value` after
theyve been moved into the hash map with the call to `insert`.
@ -924,7 +930,7 @@ scores.insert(String::from("Blue"), 25);
println!("{:?}", scores);
```
Replacing a value stored with a particular key
Listing 8-23: Replacing a value stored with a particular key
This code will print `{"Blue": 25}`. The original value of `10` has been
overwritten.
@ -955,7 +961,8 @@ scores.entry(String::from("Blue")).or_insert(50);
println!("{:?}", scores);
```
Using the `entry` method to only insert if the key does not already have a value
Listing 8-24: Using the `entry` method to only insert if the key does not
already have a value
The `or_insert` method on `Entry` is defined to return a mutable reference to
the value for the corresponding `Entry` key if that key exists, and if not, it
@ -993,7 +1000,8 @@ for word in text.split_whitespace() {
println!("{:?}", map);
```
Counting occurrences of words using a hash map that stores words and counts
Listing 8-25: Counting occurrences of words using a hash map that stores words
and counts
This code will print `{"world": 2, "hello": 1, "wonderful": 1}`. You might see
the same keyvalue pairs printed in a different order: recall from “Accessing

View File

@ -108,8 +108,8 @@ fn main() {
}
```
Attempting to access an element beyond the end of a vector, which will cause a
call to `panic!`
Listing 9-1: Attempting to access an element beyond the end of a vector, which
will cause a call to `panic!`
Here, were attempting to access the 100th element of our vector (which is at
index 99 because indexing starts at zero), but the vector has only three
@ -181,8 +181,8 @@ note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose
backtrace.
```
The backtrace generated by a call to `panic!` displayed when the environment
variable `RUST_BACKTRACE` is set
Listing 9-2: The backtrace generated by a call to `panic!` displayed when the
environment variable `RUST_BACKTRACE` is set
Thats a lot of output! The exact output you see might be different depending
on your operating system and Rust version. In order to get backtraces with this
@ -243,7 +243,7 @@ fn main() {
}
```
Opening a file
Listing 9-3: Opening a file
The return type of `File::open` is a `Result<T, E>`. The generic parameter `T`
has been filled in by the implementation of `File::open` with the type of the
@ -284,8 +284,8 @@ fn main() {
}
```
Using a `match` expression to handle the `Result` variants that might be
returned
Listing 9-4: Using a `match` expression to handle the `Result` variants that
might be returned
Note that, like the `Option` enum, the `Result` enum and its variants have been
brought into scope by the prelude, so we dont need to specify `Result::`
@ -351,7 +351,7 @@ fn main() {
}
```
Handling different kinds of errors in different ways
Listing 9-5: Handling different kinds of errors in different ways
The type of the value that `File::open` returns inside the `Err` variant is
`io::Error`, which is a struct provided by the standard library. This struct
@ -501,7 +501,7 @@ use std::io::{self, Read};
}
```
A function that returns errors to the calling code using `match`
Listing 9-6: A function that returns errors to the calling code using `match`
This function can be written in a much shorter way, but were going to start by
doing a lot of it manually in order to explore error handling; at the end,
@ -574,7 +574,8 @@ fn read_username_from_file() -> Result<String, io::Error> {
}
```
A function that returns errors to the calling code using the `?` operator
Listing 9-7: A function that returns errors to the calling code using the `?`
operator
The `?` placed after a `Result` value is defined to work in almost the same way
as the `match` expressions we defined to handle the `Result` values in Listing
@ -626,7 +627,7 @@ fn read_username_from_file() -> Result<String, io::Error> {
}
```
Chaining method calls after the `?` operator
Listing 9-8: Chaining method calls after the `?` operator
Weve moved the creation of the new `String` in `username` to the beginning of
the function; that part hasnt changed. Instead of creating a variable
@ -650,7 +651,8 @@ fn read_username_from_file() -> Result<String, io::Error> {
}
```
Using `fs::read_to_string` instead of opening and then reading the file
Listing 9-9: Using `fs::read_to_string` instead of opening and then reading the
file
Reading a file into a string is a fairly common operation, so the standard
library provides the convenient `fs::read_to_string` function that opens the
@ -683,8 +685,8 @@ fn main() {
}
```
Attempting to use the `?` in the `main` function that returns `()` wont
compile.
Listing 9-10: Attempting to use the `?` in the `main` function that returns
`()` wont compile.
This code opens a file, which might fail. The `?` operator follows the `Result`
value returned by `File::open`, but this `main` function has the return type of
@ -733,7 +735,7 @@ fn last_char_of_first_line(text: &str) -> Option<char> {
}
```
Using the `?` operator on an `Option<T>` value
Listing 9-11: Using the `?` operator on an `Option<T>` value
This function returns `Option<char>` because its possible that there is a
character there, but its also possible that there isnt. This code takes the
@ -786,8 +788,8 @@ fn main() -> Result<(), Box<dyn Error>> {
}
```
Changing `main` to return `Result<(), E>` allows the use of the `?` operator on
`Result` values.
Listing 9-12: Changing `main` to return `Result<(), E>` allows the use of the
`?` operator on `Result` values.
The `Box<dyn Error>` type is a *trait object*, which well talk about in “Using
Trait Objects That Allow for Values of Different Types” on page XX. For now,
@ -1024,7 +1026,8 @@ impl Guess {
}
```
A `Guess` type that will only continue with values between 1 and 100
Listing 9-13: A `Guess` type that will only continue with values between 1 and
100
First we define a struct named `Guess` that has a field named `value` that
holds an `i32` [1]. This is where the number will be stored.

View File

@ -68,7 +68,7 @@ fn main() {
}
```
Finding the largest number in a list of numbers
Listing 10-1: Finding the largest number in a list of numbers
We store a list of integers in the variable `number_list` [1] and place a
reference to the first number in the list in a variable named `largest` [2]. We
@ -113,7 +113,7 @@ fn main() {
}
```
Code to find the largest number in *two* lists of numbers
Listing 10-2: Code to find the largest number in *two* lists of numbers
Although this code works, duplicating code is tedious and error prone. We also
have to remember to update the code in multiple places when we want to change
@ -157,7 +157,7 @@ fn main() {
}
```
Abstracted code to find the largest number in two lists
Listing 10-3: Abstracted code to find the largest number in two lists
The `largest` function has a parameter called `list`, which represents any
concrete slice of `i32` values we might pass into the function. As a result,
@ -236,8 +236,8 @@ fn main() {
}
```
Two functions that differ only in their names and in the types in their
signatures
Listing 10-4: Two functions that differ only in their names and in the types in
their signatures
The `largest_i32` function is the one we extracted in Listing 10-3 that finds
the largest `i32` in a slice. The `largest_char` function finds the largest
@ -300,7 +300,8 @@ fn main() {
}
```
The `largest` function using generic type parameters; this doesnt compile yet
Listing 10-5: The `largest` function using generic type parameters; this
doesnt compile yet
If we compile this code right now, well get this error:
@ -350,7 +351,7 @@ fn main() {
}
```
A `Point<T>` struct that holds `x` and `y` values of type `T`
Listing 10-6: A `Point<T>` struct that holds `x` and `y` values of type `T`
The syntax for using generics in struct definitions is similar to that used in
function definitions. First we declare the name of the type parameter inside
@ -377,8 +378,8 @@ fn main() {
}
```
The fields `x` and `y` must be the same type because both have the same generic
data type `T`.
Listing 10-7: 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
@ -414,8 +415,8 @@ fn main() {
}
```
A `Point<T, U>` generic over two types so that `x` and `y` can be values of
different types
Listing 10-8: A `Point<T, U>` generic over two types so that `x` and `y` can be
values of different types
Now all the instances of `Point` shown are allowed! You can use as many generic
type parameters in a definition as you want, but using more than a few makes
@ -493,8 +494,8 @@ fn main() {
}
```
Implementing a method named `x` on the `Point<T>` struct that will return a
reference to the `x` field of type `T`
Listing 10-9: Implementing a method named `x` on the `Point<T>` struct that
will return a reference to the `x` field of type `T`
Here, weve defined a method named `x` on `Point<T>` that returns a reference
to the data in the field `x`.
@ -524,8 +525,8 @@ impl Point<f32> {
}
```
An `impl` block that only applies to a struct with a particular concrete type
for the generic type parameter `T`
Listing 10-10: An `impl` block that only applies to a struct with a particular
concrete type for the generic type parameter `T`
This code means the type `Point<f32>` will have a `distance_from_origin`
method; other instances of `Point<T>` where `T` is not of type `f32` will not
@ -570,7 +571,8 @@ fn main() {
}
```
A method that uses generic types different from its structs definition
Listing 10-11: A method that uses generic types different from its structs
definition
In `main`, weve defined a `Point` that has an `i32` for `x` (with value `5`)
and an `f64` for `y` (with value `10.4` [3]). The `p2` variable is a `Point`
@ -682,7 +684,8 @@ pub trait Summary {
}
```
A `Summary` trait that consists of the behavior provided by a `summarize` method
Listing 10-12: 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. We also declare the trait as `pub` so that
@ -745,7 +748,8 @@ impl Summary for Tweet {
}
```
Implementing the `Summary` trait on the `NewsArticle` and `Tweet` types
Listing 10-13: Implementing the `Summary` trait on the `NewsArticle` and
`Tweet` types
Implementing a trait on a type is similar to implementing regular methods. The
difference is that after `impl`, we put the trait name we want to implement,
@ -823,8 +827,8 @@ pub trait Summary {
}
```
Defining a `Summary` trait with a default implementation of the `summarize`
method
Listing 10-14: Defining a `Summary` trait with a default implementation of the
`summarize` method
To use a default implementation to summarize instances of `NewsArticle`, we
specify an empty `impl` block with `impl Summary for NewsArticle {}`.
@ -1126,7 +1130,8 @@ impl<T: Display + PartialOrd> Pair<T> {
}
```
Conditionally implementing methods on a generic type depending on trait bounds
Listing 10-15: Conditionally implementing methods on a generic type depending
on trait bounds
We can also conditionally implement a trait for any type that implements
another trait. Implementations of a trait on any type that satisfies the trait
@ -1205,7 +1210,7 @@ fn main() {
}
```
An attempt to use a reference whose value has gone out of scope
Listing 10-16: An attempt to use a reference whose value has gone out of scope
> Note: The examples in Listing 10-16, 10-17, and 10-23 declare variables
without giving them an initial value, so the variable name exists in the outer
@ -1261,7 +1266,8 @@ fn main() {
} // ---------+
```
Annotations of the lifetimes of `r` and `x`, named `'a` and `'b`, respectively
Listing 10-17: Annotations of the lifetimes of `r` and `x`, named `'a` and
`'b`, respectively
Here, weve annotated the lifetime of `r` with `'a` and the lifetime of `x`
with `'b`. As you can see, the inner `'b` block is much smaller than the outer
@ -1284,7 +1290,8 @@ fn main() {
} // ----------+
```
A valid reference because the data has a longer lifetime than the reference
Listing 10-18: A valid reference because the data has a longer lifetime than
the reference
Here, `x` has the lifetime `'b`, which in this case is larger than `'a`. This
means `r` can reference `x` because Rust knows that the reference in `r` will
@ -1313,8 +1320,8 @@ fn main() {
}
```
A `main` function that calls the `longest` function to find the longer of two
string slices
Listing 10-19: A `main` function that calls the `longest` function to find the
longer of two string slices
Note that we want the function to take string slices, which are references,
rather than strings, because we dont want the `longest` function to take
@ -1337,8 +1344,8 @@ fn longest(x: &str, y: &str) -> &str {
}
```
An implementation of the `longest` function that returns the longer of two
string slices but does not yet compile
Listing 10-20: An implementation of the `longest` function that returns the
longer of two string slices but does not yet compile
Instead, we get the following error that talks about lifetimes:
@ -1427,8 +1434,8 @@ fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
}
```
The `longest` function definition specifying that all the references in the
signature must have the same lifetime `'a`
Listing 10-21: The `longest` function definition specifying that all the
references in the signature must have the same lifetime `'a`
This code should compile and produce the result we want when we use it with the
`main` function in Listing 10-19.
@ -1486,8 +1493,8 @@ fn main() {
}
```
Using the `longest` function with references to `String` values that have
different concrete lifetimes
Listing 10-22: Using the `longest` function with references to `String` values
that have different concrete lifetimes
In this example, `string1` is valid until the end of the outer scope, `string2`
is valid until the end of the inner scope, and `result` references something
@ -1517,7 +1524,7 @@ fn main() {
}
```
Attempting to use `result` after `string2` has gone out of scope
Listing 10-23: Attempting to use `result` after `string2` has gone out of scope
When we try to compile this code, we get this error:
@ -1645,7 +1652,7 @@ fn main() {
}
```
A struct that holds a reference, requiring a lifetime annotation
Listing 10-24: A struct that holds a reference, requiring a lifetime annotation
This struct has the single field `part` that holds a string slice, which is a
reference [2]. As with generic data types, we declare the name of the generic
@ -1684,8 +1691,8 @@ fn first_word(s: &str) -> &str {
}
```
A function we defined in Listing 4-9 that compiled without lifetime
annotations, even though the parameter and return type are references
Listing 10-25: A function we defined in Listing 4-9 that compiled without
lifetime annotations, even though the parameter and return type are references
The reason this function compiles without lifetime annotations is historical:
in early versions (pre-1.0) of Rust, this code wouldnt have compiled because

View File

@ -98,7 +98,8 @@ mod tests {
}
```
The test module and function generated automatically by `cargo new`
Listing 11-1: The test module and function generated automatically by `cargo
new`
For now, lets ignore the top two lines and focus on the function. Note the
`#[test]` annotation [1]: this attribute indicates this is a test function, so
@ -136,7 +137,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0
filtered out; finished in 0.00s
```
The output from running the automatically generated test
Listing 11-2: The output from running the automatically generated test
Cargo compiled and ran the test. We see the line `running 1 test` [1]. The next
line shows the name of the generated test function, called `it_works`, and that
@ -216,7 +217,8 @@ mod tests {
}
```
Adding a second test that will fail because we call the `panic!` macro
Listing 11-3: Adding a second test that will fail because we call the `panic!`
macro
Run the tests again using `cargo test`. The output should look like Listing
11-4, which shows that our `exploration` test passed and `another` failed.
@ -242,7 +244,7 @@ filtered out; finished in 0.00s
error: test failed, to rerun pass '--lib'
```
Test results when one test passes and one test fails
Listing 11-4: Test results when one test passes and one test fails
Instead of `ok`, the line `test tests::another` shows `FAILED` [1]. Two new
sections appear between the individual results and the summary: the first [2]
@ -289,7 +291,8 @@ impl Rectangle {
}
```
Using the `Rectangle` struct and its `can_hold` method from Chapter 5
Listing 11-5: Using the `Rectangle` struct and its `can_hold` method from
Chapter 5
The `can_hold` method returns a Boolean, which means its a perfect use case
for the `assert!` macro. In Listing 11-6, we write a test that exercises the
@ -320,8 +323,8 @@ mod tests {
}
```
A test for `can_hold` that checks whether a larger rectangle can indeed hold a
smaller rectangle
Listing 11-6: A test for `can_hold` that checks whether a larger rectangle can
indeed hold a smaller rectangle
Note that weve added a new line inside the `tests` module: `use super::*;`
[1]. The `tests` module is a regular module that follows the usual visibility
@ -465,7 +468,7 @@ mod tests {
}
```
Testing the function `add_two` using the `assert_eq!` macro
Listing 11-7: Testing the function `add_two` using the `assert_eq!` macro
Lets check that it passes!
@ -692,7 +695,7 @@ mod tests {
}
```
Testing that a condition will cause a panic!
Listing 11-8: Testing that a condition will cause a panic!
We place the `#[should_panic]` attribute after the `#[test]` attribute and
before the test function it applies to. Lets look at the result when this test
@ -792,7 +795,8 @@ mod tests {
}
```
Testing for a `panic!` with a panic message containing a specified substring
Listing 11-9: Testing for a `panic!` with a panic message containing a
specified substring
This test will pass because the value we put in the `should_panic` attributes
`expected` parameter is a substring of the message that the `Guess::new`
@ -980,7 +984,7 @@ mod tests {
}
```
Tests for a function that calls `println!`
Listing 11-10: Tests for a function that calls `println!`
When we run these tests with `cargo test`, well see the following output:
@ -1091,7 +1095,7 @@ mod tests {
}
```
Three tests with three different names
Listing 11-11: Three tests with three different names
If we run the tests without passing any arguments, as we saw earlier, all the
tests will run in parallel:
@ -1310,7 +1314,7 @@ mod tests {
}
```
Testing a private function
Listing 11-12: Testing a private function
Note that the `internal_adder` function is not marked as `pub`. Tests are just
Rust code, and the `tests` module is just another module. As we discussed in
@ -1364,7 +1368,7 @@ fn it_adds_two() {
}
```
An integration test of a function in the `adder` crate
Listing 11-13: An integration test of a function in the `adder` crate
Each file in the *tests* directory is a separate crate, so we need to bring our
library into each test crates scope. For that reason we add `use adder;` at

View File

@ -98,7 +98,8 @@ fn main() {
}
```
Collecting the command line arguments into a vector and printing them
Listing 12-1: Collecting the command line arguments into a vector and printing
them
First we bring the `std::env` module into scope with a `use` statement so we
can use its `args` function. Notice that the `std::env::args` function is
@ -176,7 +177,8 @@ fn main() {
}
```
Creating variables to hold the query argument and file path argument
Listing 12-2: 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
@ -227,7 +229,7 @@ To tell your name the livelong day
To an admiring bog!
```
A poem by Emily Dickinson makes a good test case.
Listing 12-3: A poem by Emily Dickinson makes a good test case.
With the text in place, edit *src/main.rs* and add code to read the file, as
shown in Listing 12-4.
@ -249,7 +251,7 @@ fn main() {
}
```
Reading the contents of the file specified by the second argument
Listing 12-4: Reading the contents of the file specified by the second argument
First we bring in a relevant part of the standard library with a `use`
statement: we need `std::fs` to handle files [1].
@ -385,7 +387,7 @@ fn parse_config(args: &[String]) -> (&str, &str) {
}
```
Extracting a `parse_config` function from `main`
Listing 12-5: Extracting a `parse_config` function from `main`
Were still collecting the command line arguments into a vector, but instead of
assigning the argument value at index 1 to the variable `query` and the
@ -450,7 +452,8 @@ fn main() {
}
```
Refactoring `parse_config` to return an instance of a `Config` struct
Listing 12-6: Refactoring `parse_config` to return an instance of a `Config`
struct
Weve added a struct named `Config` defined to have fields named `query` and
`file_path` [5]. The signature of `parse_config` now indicates that it returns
@ -533,7 +536,7 @@ fn main() {
}
```
Changing `parse_config` into `Config::new`
Listing 12-7: Changing `parse_config` into `Config::new`
Weve updated `main` where we were calling `parse_config` to instead call
`Config::new` [1]. Weve changed the name of `parse_config` to `new` [3] and
@ -579,7 +582,7 @@ fn new(args: &[String]) -> Config {
--snip--
```
Adding a check for the number of arguments
Listing 12-8: Adding a check for the number of arguments
This code is similar to the `Guess::new` function we wrote in Listing 9-13,
where we called `panic!` when the `value` argument was out of the range of
@ -644,7 +647,7 @@ impl Config {
}
```
Returning a `Result` from `Config::build`
Listing 12-9: Returning a `Result` from `Config::build`
Our `build` function returns a `Result` with a `Config` instance in the success
case and an `&'static str` in the error case. Our error values will always be
@ -684,7 +687,7 @@ fn main() {
--snip--
```
Exiting with an error code if building a `Config` fails
Listing 12-10: Exiting with an error code if building a `Config` fails
In this listing, weve used a method we havent covered in detail yet:
`unwrap_or_else`, which is defined on `Result<T, E>` by the standard library
@ -754,7 +757,8 @@ fn run(config: Config) {
--snip--
```
Extracting a `run` function containing the rest of the program logic
Listing 12-11: Extracting a `run` function containing the rest of the program
logic
The `run` function now contains all the remaining logic from `main`, starting
from reading the file. The `run` function takes the `Config` instance as an
@ -786,7 +790,7 @@ Filename: src/main.rs
}
```
Changing the `run` function to return `Result`
Listing 12-12: Changing the `run` function to return `Result`
Weve made three significant changes here. First, we changed the return type of
the `run` function to `Result<(), Box<dyn Error>>` [2]. This function
@ -904,7 +908,7 @@ pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
}
```
Moving `Config` and `run` into *src/lib.rs*
Listing 12-13: Moving `Config` and `run` into *src/lib.rs*
Weve made liberal use of the `pub` keyword: on `Config`, on its fields and its
`build` method, and on the `run` function. We now have a library crate that has
@ -929,7 +933,7 @@ fn main() {
}
```
Using the `minigrep` library crate in *src/main.rs*
Listing 12-14: Using the `minigrep` library crate in *src/main.rs*
We add a `use minigrep::Config` line to bring the `Config` type from the
library crate into the binary crates scope, and we prefix the `run` function
@ -1003,7 +1007,7 @@ Pick three.";
}
```
Creating a failing test for the `search` function we wish we had
Listing 12-15: Creating a failing test for the `search` function we wish we had
This test searches for the string `"duct"`. The text were searching is three
lines, only one of which contains `"duct"` (note that the backslash after the
@ -1030,7 +1034,8 @@ pub fn search<'a>(
}
```
Defining just enough of the `search` function so our test will compile
Listing 12-16: Defining just enough of the `search` function so our test will
compile
Notice that we need to define an explicit lifetime `'a` in the signature of
`search` and use that lifetime with the `contents` argument and the return
@ -1144,7 +1149,7 @@ pub fn search<'a>(
}
```
Iterating through each line in `contents`
Listing 12-17: Iterating through each line in `contents`
The `lines` method returns an iterator. Well talk about iterators in depth in
Chapter 13, but recall that you saw this way of using an iterator in Listing
@ -1173,7 +1178,8 @@ pub fn search<'a>(
}
```
Adding functionality to see whether the line contains the string in `query`
Listing 12-18: Adding functionality to see whether the line contains the string
in `query`
At the moment, were building up functionality. To get the code to compile, we
need to return a value from the body as we indicated we would in the function
@ -1205,7 +1211,7 @@ pub fn search<'a>(
}
```
Storing the lines that match so we can return them
Listing 12-19: Storing the lines that match so we can return them
Now the `search` function should return only the lines that contain `query`,
and our test should pass. Lets run the test:
@ -1348,7 +1354,8 @@ Trust me.";
}
```
Adding a new failing test for the case-insensitive function were about to add
Listing 12-20: Adding a new failing test for the case-insensitive function
were about to add
Note that weve edited the old tests `contents` too. Weve added a new line
with the text `"Duct tape."` using a capital *D* that shouldnt match the query
@ -1393,8 +1400,8 @@ pub fn search_case_insensitive<'a>(
}
```
Defining the `search_case_insensitive` function to lowercase the query and the
line before comparing them
Listing 12-21: Defining the `search_case_insensitive` function to lowercase the
query and the line before comparing them
First we lowercase the `query` string and store it in a shadowed variable with
the same name [1]. Calling `to_lowercase` on the query is necessary so that no
@ -1469,8 +1476,8 @@ pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
}
```
Calling either `search` or `search_case_insensitive` based on the value in
`config.ignore_case`
Listing 12-22: Calling either `search` or `search_case_insensitive` based on
the value in `config.ignore_case`
Finally, we need to check for the environment variable. The functions for
working with environment variables are in the `env` module in the standard
@ -1507,7 +1514,8 @@ impl Config {
}
```
Checking for any value in an environment variable named `IGNORE_CASE`
Listing 12-23: Checking for any value in an environment variable named
`IGNORE_CASE`
Here, we create a new variable, `ignore_case`. To set its value, we call the
`env::var` function and pass it the name of the `IGNORE_CASE` environment
@ -1661,8 +1669,8 @@ fn main() {
}
```
Writing error messages to standard error instead of standard output using
`eprintln!`
Listing 12-24: Writing error messages to standard error instead of standard
output using `eprintln!`
Lets now run the program again in the same way, without any arguments and
redirecting standard output with `>`:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,8 @@
<!-- 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/`.
-->
## About the Authors
Carol Nichols is a member of the Rust Crates.io Team and a former member of the
@ -100,6 +105,7 @@ multiple files with modules.
captures, the `move` keyword, and the `Fn` traits.
* We fixed a number of small errors and imprecise wording throughout the book.
Thank you to the readers who reported them!
Note that any code from earlier renditions of this book that compiled will
continue to compile with the relevant edition in the projects *Cargo.toml*,
even as you update the Rust compiler version youre using. Thats Rusts
@ -136,10 +142,11 @@ Rust also brings contemporary developer tools to the systems programming world:
* Cargo, the included dependency manager and build tool, makes adding,
compiling, and managing dependencies painless and consistent across the Rust
ecosystem.
* The `r``ustfmt` formatting tool ensures a consistent coding style across
* The `rustfmt` formatting tool ensures a consistent coding style across
developers.
* The Rust Language Server powers integrated development environment (IDE)
integration for code completion and inline error messages.
By using these and other tools in the Rust ecosystem, developers can be
productive while writing systems-level code.