Backport changes from print for ch7

This commit is contained in:
Carol (Nichols || Goulding) 2024-04-25 15:59:23 -04:00 committed by Carol (Nichols || Goulding)
parent d207d894cc
commit 98165c4279
5 changed files with 88 additions and 88 deletions

View File

@ -35,12 +35,13 @@ package also contains a library crate that the binary crate depends on. Other
projects can depend on the Cargo library crate to use the same logic the Cargo
command-line tool uses.
A package can contain as many binary crates as you like, but at most only one
A crate can come in one of two forms: a binary crate or a library crate. A
package can contain as many binary crates as you like, but at most only one
library crate. A package must contain at least one crate, whether thats a
library or binary crate.
Lets walk through what happens when we create a package. First, we enter the
command `cargo new`:
Lets walk through what happens when we create a package. First we enter the
command `cargo new my-project`:
```console
$ cargo new my-project
@ -52,15 +53,15 @@ $ ls my-project/src
main.rs
```
After we run `cargo new`, we use `ls` to see what Cargo creates. In the project
directory, theres a *Cargo.toml* file, giving us a package. Theres also a
*src* directory that contains *main.rs*. Open *Cargo.toml* in your text editor,
and note theres no mention of *src/main.rs*. Cargo follows a convention that
*src/main.rs* is the crate root of a binary crate with the same name as the
package. Likewise, Cargo knows that if the package directory contains
*src/lib.rs*, the package contains a library crate with the same name as the
package, and *src/lib.rs* is its crate root. Cargo passes the crate root files
to `rustc` to build the library or binary.
After we run `cargo new my-project`, we use `ls` to see what Cargo creates. In
the project directory, theres a *Cargo.toml* file, giving us a package.
Theres also a *src* directory that contains *main.rs*. Open *Cargo.toml* in
your text editor, and note theres no mention of *src/main.rs*. Cargo follows a
convention that *src/main.rs* is the crate root of a binary crate with the same
name as the package. Likewise, Cargo knows that if the package directory
contains *src/lib.rs*, the package contains a library crate with the same name
as the package, and *src/lib.rs* is its crate root. Cargo passes the crate root
files to `rustc` to build the library or binary.
Here, we have a package that only contains *src/main.rs*, meaning it only
contains a binary crate named `my-project`. If a package contains *src/main.rs*

View File

@ -1,27 +1,23 @@
## Defining Modules to Control Scope and Privacy
In this section, well talk about modules and other parts of the module system,
namely *paths* that allow you to name items; the `use` keyword that brings a
namely *paths*, which allow you to name items; the `use` keyword that brings a
path into scope; and the `pub` keyword to make items public. Well also discuss
the `as` keyword, external packages, and the glob operator.
First, were going to start with a list of rules for easy reference when youre
organizing your code in the future. Then well explain each of the rules in
detail.
### Modules Cheat Sheet
Here we provide a quick reference on how modules, paths, the `use` keyword, and
the `pub` keyword work in the compiler, and how most developers organize their
code. Well be going through examples of each of these rules throughout this
chapter, but this is a great place to refer to as a reminder of how modules
work.
Before we get to the details of modules and paths, here we provide a quick
reference on how modules, paths, the `use` keyword, and the `pub` keyword work
in the compiler, and how most developers organize their code. Well be going
through examples of each of these rules throughout this chapter, but this is a
great place to refer to as a reminder of how modules work.
- **Start from the crate root**: When compiling a crate, the compiler first
looks in the crate root file (usually *src/lib.rs* for a library crate or
*src/main.rs* for a binary crate) for code to compile.
- **Declaring modules**: In the crate root file, you can declare new modules;
say, you declare a “garden” module with `mod garden;`. The compiler will look
say you declare a “garden” module with `mod garden;`. The compiler will look
for the modules code in these places:
- Inline, within curly brackets that replace the semicolon following `mod
garden`
@ -40,7 +36,7 @@ for the modules code in these places:
as the privacy rules allow, using the path to the code. For example, an
`Asparagus` type in the garden vegetables module would be found at
`crate::garden::vegetables::Asparagus`.
- **Private vs public**: Code within a module is private from its parent
- **Private vs. public**: Code within a module is private from its parent
modules by default. To make a module public, declare it with `pub mod`
instead of `mod`. To make items within a public module public as well, use
`pub` before their declarations.
@ -50,8 +46,9 @@ for the modules code in these places:
crate::garden::vegetables::Asparagus;` and from then on you only need to
write `Asparagus` to make use of that type in the scope.
Here we create a binary crate named `backyard` that illustrates these rules. The
crates directory, also named `backyard`, contains these files and directories:
Here, we create a binary crate named `backyard` that illustrates these rules.
The crates directory, also named `backyard`, contains these files and
directories:
```text
backyard
@ -93,7 +90,7 @@ Now lets get into the details of these rules and demonstrate them in action!
### Grouping Related Code in Modules
*Modules* let us organize code within a crate for readability and easy reuse.
Modules also allow us to control the *privacy* of items, because code within a
Modules also allow us to control the *privacy* of items because code within a
module is private by default. Private items are internal implementation details
not available for outside use. We can choose to make modules and the items
within them public, which exposes them to allow external code to use and depend
@ -101,7 +98,7 @@ on them.
As an example, lets write a library crate that provides the functionality of a
restaurant. Well define the signatures of functions but leave their bodies
empty to concentrate on the organization of the code, rather than the
empty to concentrate on the organization of the code rather than the
implementation of a restaurant.
In the restaurant industry, some parts of a restaurant are referred to as
@ -113,8 +110,9 @@ administrative work.
To structure our crate in this way, we can organize its functions into nested
modules. Create a new library named `restaurant` by running `cargo new
restaurant --lib`; then enter the code in Listing 7-1 into *src/lib.rs* to
define some modules and function signatures. Heres the front of house section:
restaurant --lib`. Then enter the code in Listing 7-1 into *src/lib.rs* to
define some modules and function signatures; this code is the front of house
section.
<span class="filename">Filename: src/lib.rs</span>
@ -160,13 +158,13 @@ crate
<span class="caption">Listing 7-2: The module tree for the code in Listing
7-1</span>
This tree shows how some of the modules nest inside one another; for example,
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
are *siblings* to each other, meaning theyre defined in the same module;
`hosting` and `serving` are siblings defined within `front_of_house`. If module
A is contained inside module B, we say that module A is the *child* of module B
and that module B is the *parent* of module A. Notice that the entire module
tree is rooted under the implicit module named `crate`.
are *siblings*, meaning theyre defined in the same module; `hosting` and
`serving` are siblings defined within `front_of_house`. If module A is
contained inside module B, we say that module A is the *child* of module B and
that module B is the *parent* of module A. Notice that the entire module tree
is rooted under the implicit module named `crate`.
The module tree might remind you of the filesystems directory tree on your
computer; this is a very apt comparison! Just like directories in a filesystem,

View File

@ -20,10 +20,10 @@ This is the same as asking: whats the path of the `add_to_waitlist` function?
Listing 7-3 contains Listing 7-1 with some of the modules and functions
removed.
Well show two ways to call the `add_to_waitlist` function from a new function
`eat_at_restaurant` defined in the crate root. These paths are correct, but
Well show two ways to call the `add_to_waitlist` function from a new function,
`eat_at_restaurant`, defined in the crate root. These paths are correct, but
theres another problem remaining that will prevent this example from compiling
as-is. Well explain why in a bit.
as is. Well explain why in a bit.
The `eat_at_restaurant` function is part of our library crates public API, so
we mark it with the `pub` keyword. In the [“Exposing Paths with the `pub`
@ -55,19 +55,20 @@ filesystem equivalent would be using the path
that the path is relative.
Choosing whether to use a relative or absolute path is a decision youll make
based on your project, and depends on whether youre more likely to move item
definition code separately from or together with the code that uses the item.
For example, if we move the `front_of_house` module and the `eat_at_restaurant`
function into a module named `customer_experience`, wed need to update the
absolute path to `add_to_waitlist`, but the relative path would still be valid.
However, if we moved the `eat_at_restaurant` function separately into a module
named `dining`, the absolute path to the `add_to_waitlist` call would stay the
same, but the relative path would need to be updated. Our preference in general
is to specify absolute paths because its more likely well want to move code
definitions and item calls independently of each other.
based on your project, and it depends on whether youre more likely to move
item definition code separately from or together with the code that uses the
item. For example, if we moved the `front_of_house` module and the
`eat_at_restaurant` function into a module named `customer_experience`, wed
need to update the absolute path to `add_to_waitlist`, but the relative path
would still be valid. However, if we moved the `eat_at_restaurant` function
separately into a module named `dining`, the absolute path to the
`add_to_waitlist` call would stay the same, but the relative path would need to
be updated. Our preference in general is to specify absolute paths because its
more likely well want to move code definitions and item calls independently of
each other.
Lets try to compile Listing 7-3 and find out why it wont compile yet! The
error we get is shown in Listing 7-4.
errors we get are shown in Listing 7-4.
```console
{{#include ../listings/ch07-managing-growing-projects/listing-07-03/output.txt}}
@ -113,8 +114,8 @@ access to the `add_to_waitlist` function in the child module, so we mark the
<span class="caption">Listing 7-5: Declaring the `hosting` module as `pub` to
use it from `eat_at_restaurant`</span>
Unfortunately, the code in Listing 7-5 still results in an error, as shown in
Listing 7-6.
Unfortunately, the code in Listing 7-5 still results in compiler errors, as
shown in Listing 7-6.
```console
{{#include ../listings/ch07-managing-growing-projects/listing-07-05/output.txt}}
@ -180,13 +181,13 @@ interested in this topic, see [The Rust API Guidelines][api-guidelines].
> #### Best Practices for Packages with a Binary and a Library
>
> We mentioned a package can contain both a *src/main.rs* binary crate root as
> well as a *src/lib.rs* library crate root, and both crates will have the
> package name by default. Typically, packages with this pattern of containing
> both a library and a binary crate will have just enough code in the binary
> crate to start an executable that calls code within the library crate. This
> lets other projects benefit from most of the functionality that the package
> provides, because the library crates code can be shared.
> We mentioned that a package can contain both a *src/main.rs* binary crate
> root as well as a *src/lib.rs* library crate root, and both crates will have
> the package name by default. Typically, packages with this pattern of
> containing both a library and a binary crate will have just enough code in the
> binary crate to start an executable that calls code within the library crate.
> This lets other projects benefit from most of the functionality that the
> package provides because the library crates code can be shared.
>
> The module tree should be defined in *src/lib.rs*. Then, any public items can
> be used in the binary crate by starting paths with the name of the package.
@ -206,14 +207,14 @@ the current module or the crate root, by using `super` at the start of the
path. This is like starting a filesystem path with the `..` syntax. Using
`super` allows us to reference an item that we know is in the parent module,
which can make rearranging the module tree easier when the module is closely
related to the parent, but the parent might be moved elsewhere in the module
related to the parent but the parent might be moved elsewhere in the module
tree someday.
Consider the code in Listing 7-8 that models the situation in which a chef
fixes an incorrect order and personally brings it out to the customer. The
function `fix_incorrect_order` defined in the `back_of_house` module calls the
function `deliver_order` defined in the parent module by specifying the path to
`deliver_order` starting with `super`:
`deliver_order`, starting with `super`.
<span class="filename">Filename: src/lib.rs</span>
@ -236,7 +237,7 @@ code gets moved to a different module.
### Making Structs and Enums Public
We can also use `pub` to designate structs and enums as public, but there are a
few details extra to the usage of `pub` with structs and enums. If we use `pub`
few extra details to the usage of `pub` with structs and enums. If we use `pub`
before a struct definition, we make the struct public, but the structs fields
will still be private. We can make each field public or not on a case-by-case
basis. In Listing 7-9, weve defined a public `back_of_house::Breakfast` struct
@ -258,7 +259,7 @@ private fields</span>
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
notation. Notice that we cant use the `seasonal_fruit` field in
`eat_at_restaurant` because `seasonal_fruit` is private. Try uncommenting the
`eat_at_restaurant`, because `seasonal_fruit` is private. Try uncommenting the
line modifying the `seasonal_fruit` field value to see what error you get!
Also, note that because `back_of_house::Breakfast` has a private field, the

View File

@ -30,7 +30,7 @@ also check privacy, like any other paths.
Note that `use` only creates the shortcut for the particular scope in which the
`use` occurs. Listing 7-12 moves the `eat_at_restaurant` function into a new
child module named `customer`, which is then a different scope than the `use`
statement, so the function body wont compile:
statement, so the function body wont compile.
<span class="filename">Filename: src/lib.rs</span>
@ -57,7 +57,7 @@ the shortcut in the parent module with `super::hosting` within the child
In Listing 7-11, you might have wondered why we specified `use
crate::front_of_house::hosting` and then called `hosting::add_to_waitlist` in
`eat_at_restaurant` rather than specifying the `use` path all the way out to
`eat_at_restaurant`, rather than specifying the `use` path all the way out to
the `add_to_waitlist` function to achieve the same result, as in Listing 7-13.
<span class="filename">Filename: src/lib.rs</span>
@ -69,9 +69,9 @@ the `add_to_waitlist` function to achieve the same result, as in Listing 7-13.
<span class="caption">Listing 7-13: Bringing the `add_to_waitlist` function
into scope with `use`, which is unidiomatic</span>
Although both Listing 7-11 and 7-13 accomplish the same task, Listing 7-11 is
the idiomatic way to bring a function into scope with `use`. Bringing the
functions parent module into scope with `use` means we have to specify the
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
the functions parent module into scope with `use` means we have to specify the
parent module when calling the function. Specifying the parent module when
calling the function makes it clear that the function isnt locally defined
while still minimizing repetition of the full path. The code in Listing 7-13 is
@ -97,7 +97,7 @@ emerged, and folks have gotten used to reading and writing Rust code this way.
The exception to this idiom is if were bringing two items with the same name
into scope with `use` statements, because Rust doesnt allow that. Listing 7-15
shows how to bring two `Result` types into scope that have the same name but
different parent modules and how to refer to them.
different parent modules, and how to refer to them.
<span class="filename">Filename: src/lib.rs</span>
@ -110,7 +110,7 @@ the same scope requires using their parent modules.</span>
As you can see, using the parent modules distinguishes the two `Result` types.
If instead we specified `use std::fmt::Result` and `use std::io::Result`, wed
have two `Result` types in the same scope and Rust wouldnt know which one we
have two `Result` types in the same scope, and Rust wouldnt know which one we
meant when we used `Result`.
### Providing New Names with the `as` Keyword
@ -139,8 +139,8 @@ considered idiomatic, so the choice is up to you!
When we bring a name into scope with the `use` keyword, the name available in
the new scope is private. To enable the code that calls our code to refer to
that name as if it had been defined in that codes scope, we can combine `pub`
and `use`. This technique is called *re-exporting* because were bringing
an item into scope but also making that item available for others to bring into
and `use`. This technique is called *re-exporting* because were bringing an
item into scope but also making that item available for others to bring into
their scope.
Listing 7-17 shows the code in Listing 7-11 with `use` in the root module
@ -160,7 +160,7 @@ function by using the path
`restaurant::front_of_house::hosting::add_to_waitlist()`, which also would have
required the `front_of_house` module to be marked as `pub`. Now that this `pub
use` has re-exported the `hosting` module from the root module, external code
can now use the path `restaurant::hosting::add_to_waitlist()` instead.
can use the path `restaurant::hosting::add_to_waitlist()` instead.
Re-exporting is useful when the internal structure of your code is different
from how programmers calling your code would think about the domain. For
@ -226,10 +226,10 @@ crate.
### Using Nested Paths to Clean Up Large `use` Lists
If were using multiple items defined in the same crate or same module,
listing each item on its own line can take up a lot of vertical space in our
files. For example, these two `use` statements we had in the Guessing Game in
Listing 2-4 bring items from `std` into scope:
If were using multiple items defined in the same crate or same module, listing
each item on its own line can take up a lot of vertical space in our files. For
example, these two `use` statements we had in the guessing game in Listing 2-4
bring items from `std` into scope:
<span class="filename">Filename: src/main.rs</span>

View File

@ -10,7 +10,7 @@ modules defined in the crate root file. In this case, the crate root file is
*src/lib.rs*, but this procedure also works with binary crates whose crate root
file is *src/main.rs*.
First, well extract the `front_of_house` module to its own file. Remove the
First well extract the `front_of_house` module to its own file. Remove the
code inside the curly brackets for the `front_of_house` module, leaving only
the `mod front_of_house;` declaration, so that *src/lib.rs* contains the code
shown in Listing 7-21. Note that this wont compile until we create the
@ -51,10 +51,10 @@ programming languages.
Next, well extract the `hosting` module to its own file. The process is a bit
different because `hosting` is a child module of `front_of_house`, not of the
root module. Well place the file for `hosting` in a new directory that will be
named for its ancestors in the module tree, in this case *src/front_of_house/*.
named for its ancestors in the module tree, in this case *src/front_of_house*.
To start moving `hosting`, we change *src/front_of_house.rs* to contain only the
declaration of the `hosting` module:
To start moving `hosting`, we change *src/front_of_house.rs* to contain only
the declaration of the `hosting` module:
<span class="filename">Filename: src/front_of_house.rs</span>
@ -62,7 +62,7 @@ declaration of the `hosting` module:
{{#rustdoc_include ../listings/ch07-managing-growing-projects/no-listing-02-extracting-hosting/src/front_of_house.rs}}
```
Then we create a *src/front_of_house* directory and a file *hosting.rs* to
Then we create a *src/front_of_house* directory and a *hosting.rs* file to
contain the definitions made in the `hosting` module:
<span class="filename">Filename: src/front_of_house/hosting.rs</span>
@ -74,7 +74,7 @@ contain the definitions made in the `hosting` module:
If we instead put *hosting.rs* in the *src* directory, the compiler would
expect the *hosting.rs* code to be in a `hosting` module declared in the crate
root, and not declared as a child of the `front_of_house` module. The
compilers rules for which files to check for which modules code means the
compilers rules for which files to check for which modules code mean the
directories and files more closely match the module tree.
> ### Alternate File Paths
@ -93,9 +93,9 @@ directories and files more closely match the module tree.
> * *src/front_of_house/hosting.rs* (what we covered)
> * *src/front_of_house/hosting/mod.rs* (older style, still supported path)
>
> If you use both styles for the same module, youll get a compiler error. Using
> a mix of both styles for different modules in the same project is allowed, but
> might be confusing for people navigating your project.
> If you use both styles for the same module, youll get a compiler error.
> Using a mix of both styles for different modules in the same project is
> allowed, but might be confusing for people navigating your project.
>
> The main downside to the style that uses files named *mod.rs* is that your
> project can end up with many files named *mod.rs*, which can get confusing
@ -114,8 +114,8 @@ that module.
## Summary
Rust lets you split a package into multiple crates and a crate into modules
so you can refer to items defined in one module from another module. You can do
Rust lets you split a package into multiple crates and a crate into modules so
you can refer to items defined in one module from another module. You can do
this by specifying absolute or relative paths. These paths can be brought into
scope with a `use` statement so you can use a shorter path for multiple uses of
the item in that scope. Module code is private by default, but you can make