mirror of https://github.com/rust-lang/book
Regenerate everything
This commit is contained in:
parent
d57b3d4764
commit
786fbf17b4
|
@ -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 we’ll 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 wouldn’t
|
||||
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)
|
||||
}
|
||||
```
|
||||
|
||||
you’ll 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 can’t 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 aren’t keywords. In addition, raw identifiers
|
||||
allow you to use libraries written in a different Rust edition than your crate
|
||||
uses. For example, `try` isn’t 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, you’ll 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.
|
||||
|
|
@ -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 Rust’s 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 don’t function as operators; that
|
||||
is, they don’t 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 it’s 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:
|
|
@ -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, we’ve 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 you’ve 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 you’re 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 don’t have sensible default behavior, so it’s up to you to
|
||||
implement them in the way that makes sense for what you’re trying to accomplish.
|
||||
|
||||
An example of a trait that can’t 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 doesn’t have this insight, so
|
||||
it can’t 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 program’s 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 weren’t
|
||||
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 don’t produce an
|
||||
ordering. An example of a value that doesn’t 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 doesn’t 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 doesn’t 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 don’t 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>`.
|
||||
|
|
@ -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. We’ll 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 that’s
|
||||
likely what you want. You’ve 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, we’re 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, we’ll 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 Clippy’s 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 doesn’t 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` project’s 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
|
||||
|
|
@ -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 doesn’t 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
|
||||
compiler’s release, and they can link crates of any supported editions
|
||||
together. Edition changes only affect the way the compiler initially parses
|
||||
code. Therefore, if you’re 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`.
|
||||
|
|
@ -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, we’ll 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* (*Tom’s Obvious, Minimal Language*) format, which is
|
||||
Cargo’s configuration format.
|
||||
|
|
|
@ -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 let’s 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, you’ve successfully built the guessing game. Congratulations!
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ Specifically, you’ll 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 you’d use `isize` or `usize` is when indexing
|
||||
some sort of collection.
|
||||
|
||||
|
||||
> ### Integer Overflow
|
||||
>
|
||||
> Let’s say you have a variable of type `u8` that can hold values between 0 and
|
||||
|
@ -852,9 +850,10 @@ understand. Other languages don’t have the same distinctions, so let’s 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. Let’s look at some examples.
|
||||
* **Statements **: are instructions that perform some action and do not return
|
||||
a value.
|
||||
* **Expressions **: evaluate to a resultant value. Let’s look at some examples.
|
||||
|
||||
We’ve 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 it’s 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, we’ll see the same output as in Listing 3-4. More
|
||||
importantly, we’ve now increased the safety of the code and eliminated the
|
||||
|
|
|
@ -47,7 +47,7 @@ struct User {
|
|||
}
|
||||
```
|
||||
|
||||
A `User` struct definition
|
||||
Listing 5-1: A `User` struct definition
|
||||
|
||||
To use a struct after we’ve 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 user’s 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 doesn’t 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, we’re creating a new instance of the `User` struct, which has a field
|
||||
named `email`. We want to set the `email` field’s 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 wouldn’t need any data to
|
|||
implement that behavior! You’ll 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
|
||||
we’re 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, we’ve defined a struct and named it `Rectangle` [1]. Inside the curly
|
||||
brackets, we defined the fields as `width` and `height`, both of which have
|
||||
|
@ -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 won’t get any errors, and we’ll 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 type’s 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.
|
||||
|
||||
|
||||
> ### Where’s 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, we’ll 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
|
||||
|
||||
There’s no reason to separate these methods into multiple `impl` blocks here,
|
||||
but this is valid syntax. We’ll see a case in which multiple `impl` blocks are
|
||||
|
|
|
@ -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, we’ve 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
|
||||
|
||||
Let’s 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
|
||||
|
||||
Let’s imagine that a friend is trying to collect all 50 state quarters. While
|
||||
we sort our loose change by coin type, we’ll 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>`
|
||||
|
||||
Let’s 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 don’t want to do anything
|
||||
|
|
|
@ -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, let’s 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 it’s in.
|
||||
Listing 7-12: A `use` statement only applies in the scope it’s 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
|
||||
|
||||
There’s no strong reason behind this idiom: it’s 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`, we’d
|
||||
|
@ -909,7 +912,7 @@ fn function2() -> IoResult<()> {
|
|||
}
|
||||
```
|
||||
|
||||
Renaming a type when it’s brought into scope with the `as` keyword
|
||||
Listing 7-16: Renaming a type when it’s 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 won’t 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 that’s 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
|
||||
|
|
|
@ -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 aren’t inserting any
|
||||
values into this vector, Rust doesn’t 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 we’ve given initial `i32` values, Rust can infer that the type of `v`
|
||||
is `Vec<i32>`, and the type annotation isn’t necessary. Next, we’ll 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, we’ll 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 don’t 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 wouldn’t be able to print
|
||||
its value on the last line. However, this code works as we’d 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 that’s associated with the Blue team, and the
|
||||
result will be `10`. The `get` method returns an `Option<&V>`; if there’s 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 they’re inserted
|
||||
Listing 8-22: Showing that keys and values are owned by the hash map once
|
||||
they’re inserted
|
||||
|
||||
We aren’t able to use the variables `field_name` and `field_value` after
|
||||
they’ve 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 key–value pairs printed in a different order: recall from “Accessing
|
||||
|
|
|
@ -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, we’re 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
|
||||
|
||||
That’s 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 don’t 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 we’re 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
|
||||
|
||||
We’ve moved the creation of the new `String` in `username` to the beginning of
|
||||
the function; that part hasn’t 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 `()` won’t
|
||||
compile.
|
||||
Listing 9-10: Attempting to use the `?` in the `main` function that returns
|
||||
`()` won’t 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 it’s possible that there is a
|
||||
character there, but it’s also possible that there isn’t. 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 we’ll 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.
|
||||
|
|
|
@ -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 doesn’t compile yet
|
||||
Listing 10-5: The `largest` function using generic type parameters; this
|
||||
doesn’t compile yet
|
||||
|
||||
If we compile this code right now, we’ll 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, we’ve 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 struct’s definition
|
||||
Listing 10-11: A method that uses generic types different from its struct’s
|
||||
definition
|
||||
|
||||
In `main`, we’ve 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 trait’s 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, we’ve 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 don’t 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 wouldn’t have compiled because
|
||||
|
|
|
@ -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, let’s 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 it’s 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 we’ve 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
|
||||
|
||||
Let’s 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. Let’s 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` attribute’s
|
||||
`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`, we’ll 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 crate’s scope. For that reason we add `use adder;` at
|
||||
|
|
|
@ -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 program’s name takes up the first
|
||||
value in the vector at `args[0]`, so we’re 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`
|
||||
|
||||
We’re 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
|
||||
|
||||
We’ve 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`
|
||||
|
||||
We’ve updated `main` where we were calling `parse_config` to instead call
|
||||
`Config::new` [1]. We’ve 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, we’ve used a method we haven’t 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`
|
||||
|
||||
We’ve 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*
|
||||
|
||||
We’ve 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 crate’s 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 we’re 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. We’ll 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, we’re 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. Let’s run the test:
|
||||
|
@ -1348,7 +1354,8 @@ Trust me.";
|
|||
}
|
||||
```
|
||||
|
||||
Adding a new failing test for the case-insensitive function we’re about to add
|
||||
Listing 12-20: Adding a new failing test for the case-insensitive function
|
||||
we’re about to add
|
||||
|
||||
Note that we’ve edited the old test’s `contents` too. We’ve added a new line
|
||||
with the text `"Duct tape."` using a capital *D* that shouldn’t 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!`
|
||||
|
||||
Let’s 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
|
@ -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 project’s *Cargo.toml*,
|
||||
even as you update the Rust compiler version you’re using. That’s Rust’s
|
||||
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in New Issue