Propagate chapter 7 edits to src

This commit is contained in:
Carol (Nichols || Goulding) 2022-05-20 21:44:10 -04:00
parent 62bda19b89
commit c77d7a1279
No known key found for this signature in database
GPG Key ID: E907EE5A736F87D4
7 changed files with 235 additions and 228 deletions

View File

@ -481,6 +481,7 @@ subdirectory
submodule
submodules
Submodules
submodules
suboptimal
subpath
substring

View File

@ -1,27 +1,26 @@
# Managing Growing Projects with Packages, Crates, and Modules
As you write large programs, organizing your code will be important because
keeping track of your entire program in your head will become impossible. By
grouping related functionality and separating code with distinct features,
youll clarify where to find code that implements a particular feature and
where to go to change how a feature works.
As you write large programs, organizing your code will become increasingly
important. By grouping related functionality and separating code with distinct
features, youll clarify where to find code that implements a particular
feature and where to go to change how a feature works.
The programs weve written so far have been in one module in one file. As a
project grows, you can organize code by splitting it into multiple modules and
then multiple files. A package can contain multiple binary crates and
project grows, you should organize code by splitting it into multiple modules
and then multiple files. A package can contain multiple binary crates and
optionally one library crate. As a package grows, you can extract parts into
separate crates that become external dependencies. This chapter covers all
these techniques. For very large projects of a set of interrelated packages
that evolve together, Cargo provides workspaces, which well cover in the
[“Cargo Workspaces”][workspaces]<!-- ignore --> section in Chapter 14.
these techniques. For very large projects comprising a set of interrelated
packages that evolve together, Cargo provides *workspaces*, which well cover
in the [“Cargo Workspaces”][workspaces]<!-- ignore --> section in Chapter 14.
In addition to grouping functionality, encapsulating implementation details
lets you reuse code at a higher level: once youve implemented an operation,
other code can call that code via the codes public interface without knowing
how the implementation works. The way you write code defines which parts are
public for other code to use and which parts are private implementation details
that you reserve the right to change. This is another way to limit the amount
of detail you have to keep in your head.
Well also discuss encapsulating implementation details, which lets you reuse
code at a higher level: once youve implemented an operation, other code can
call your code via its public interface without having to know how the
implementation works. The way you write code defines which parts are public for
other code to use and which parts are private implementation details that you
reserve the right to change. This is another way to limit the amount of detail
you have to keep in your head.
A related concept is scope: the nested context in which code is written has a
set of names that are defined as “in scope.” When reading, writing, and

View File

@ -20,16 +20,24 @@ executable. Instead, they define functionality intended to be shared with
multiple projects. For example, the `rand` crate we used in [Chapter
2][rand]<!-- ignore --> provides functionality that generates random numbers.
Most of the time when Rustaceans say “crate”, they mean library crate, and they
use “crate” interchangably with the general programming concept of a “library".
use “crate” interchangeably with the general programming concept of a “library".
The *crate root* is a source file that the Rust compiler starts from and makes
up the root module of your crate (well explain modules in depth in the
[“Defining Modules to Control Scope and Privacy”][modules]<!-- ignore -->
section).
Several rules determine what a package can contain. A package can contain at
most one library crate. It can contain as many binary crates as youd like, but
it must contain at least one crate (either library or binary).
A *package* is a bundle of one or more crates that provides a set of
functionality. A package contains a *Cargo.toml* file that describes how to
build those crates. Cargo is actually a package that contains the binary crate
for the command-line tool youve been using to build your code. The Cargo
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
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`:
@ -44,14 +52,15 @@ $ ls my-project/src
main.rs
```
When we entered the command, Cargo created a *Cargo.toml* file, giving us a
package. Looking at the contents of *Cargo.toml*, theres no mention of
*src/main.rs* because 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`, 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

@ -9,37 +9,37 @@ First, were going to start with a list of rules for easy reference when you
organizing your code in the future. Then well explain each of the rules in
detail.
### Modules Quick Reference
### Modules Cheat Sheet
Heres 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, but this is a great place to look in the
future as a reminder of how modules work.
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).
- **Declaring modules**: In the crate root file, you can declare a new module
named, say, “garden”, with `mod garden;`. The compiler will look for the code
inside the module in these places:
- **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
for the modules code in these places:
- Inline, directly following `mod garden`, within curly brackets instead of
the semicolon
- In the file *src/garden.rs*
- In the file *src/garden/mod.rs*
- **Declaring submodules**: In any file other than the crate root thats being
compiled as part of the crate (for example, *src/garden.rs*), you can declare
submodules (for example, `mod vegetables;`). The compiler will look for the
code inside submodules in these places within a directory named for the
parent module:
- **Declaring submodules**: In any file other than the crate root, you can
declare submodules. For example, you might declare `mod vegetables;` in
*src/garden.rs*. The compiler will look for the submodules code within the
directory named for the parent module in these places:
- Inline, directly following `mod vegetables`, within curly brackets instead
of the semicolon
- In the file *src/garden/vegetables.rs*
- In the file *src/garden/vegetables/mod.rs*
- **Paths to code in modules**: Once a module is being compiled as part of your
crate, you can refer to code in that module (for example, an `Asparagus` type
in the garden vegetables module) from anywhere else in this crate by using
the path `crate::garden::vegetables::Asparagus` as long as the privacy rules
allow.
- **Paths to code in modules**: Once a module is part of your crate, you can
refer to code in that module from anywhere else in that same crate, as long
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
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
@ -47,10 +47,10 @@ future as a reminder of how modules work.
- **The `use` keyword**: Within a scope, the `use` keyword creates shortcuts to
items to reduce repetition of long paths. In any scope that can refer to
`crate::garden::vegetables::Asparagus`, you can create a shortcut with `use
crate::garden::vegetables::Asparagus;` and then only need to write `Asparagus`
to make use of that type in the scope.
crate::garden::vegetables::Asparagus;` and from then on you only need to
write `Asparagus` to make use of that type in the scope.
Heres a binary crate named `backyard` that illustrates these rules. The
Here we create a binary crate named `backyard` that illustrates these rules. The
crates directory, also named `backyard`, contains these files and directories:
```text
@ -64,7 +64,7 @@ backyard
└── main.rs
```
The crate root file, in this case *src/main.rs*, contains:
The crate root file in this case is *src/main.rs*, and it contains:
<span class="filename">Filename: src/main.rs</span>
@ -72,7 +72,7 @@ The crate root file, in this case *src/main.rs*, contains:
{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/main.rs}}
```
The `pub mod garden;` means the compiler includes the code it finds in
The `pub mod garden;` line tells the compiler to include the code it finds in
*src/garden.rs*, which is:
<span class="filename">Filename: src/garden.rs</span>
@ -81,8 +81,8 @@ The `pub mod garden;` means the compiler includes the code it finds in
{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden.rs}}
```
And `pub mod vegetables;` means the code in *src/garden/vegetables.rs* is
included too:
Here, `pub mod vegetables;` means the code in *src/garden/vegetables.rs* is
included too. That code is:
```rust,noplayground,ignore
{{#rustdoc_include ../listings/ch07-managing-growing-projects/quick-reference-example/src/garden/vegetables.rs}}
@ -92,26 +92,29 @@ 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 into groups for readability and
easy reuse. Modules also control the *privacy* of items, which is whether an
item can be used by outside code (*public*) or is an internal implementation
detail and not available for outside use (*private*).
*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
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
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 actually
implement a restaurant in code.
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
*front of house* and others as *back of house*. Front of house is where
customers are; this is where hosts seat customers, servers take orders and
payment, and bartenders make drinks. Back of house is where the chefs and cooks
work in the kitchen, dishwashers clean up, and managers do administrative work.
customers are; this encompasses where the hosts seat customers, servers take
orders and payment, and bartenders make drinks. Back of house is where the
chefs and cooks work in the kitchen, dishwashers clean up, and managers do
administrative work.
To structure our crate in the same way that a real restaurant works, we can
organize the functions into nested modules. Create a new library named
`restaurant` by running `cargo new --lib restaurant`; then put the code in
Listing 7-1 into *src/lib.rs* to define some modules and function signatures.
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 --lib
restaurant`; 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:
<span class="filename">Filename: src/lib.rs</span>
@ -122,19 +125,18 @@ Listing 7-1 into *src/lib.rs* to define some modules and function signatures.
<span class="caption">Listing 7-1: A `front_of_house` module containing other
modules that then contain functions</span>
We define a module by starting with the `mod` keyword and then specify the
name of the module (in this case, `front_of_house`) and place curly brackets
around the body of the module. Inside modules, we can have other modules, as in
this case with the modules `hosting` and `serving`. Modules can also hold
definitions for other items, such as structs, enums, constants, traits, or—as
in Listing 7-1—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
brackets. Inside modules, we can place other modules, as in this case with the
modules `hosting` and `serving`. Modules can also hold definitions for other
items, such as structs, enums, constants, traits, and—as in Listing
7-1—functions.
By using modules, we can group related definitions together and name why
theyre related. Programmers using this code would have an easier time finding
the definitions they wanted to use because they could navigate the code based
on the groups rather than having to read through all the definitions.
Programmers adding new functionality to this code would know where to place the
code to keep the program organized.
theyre related. Programmers using this code can navigate the code based on the
groups rather than having to read through all the definitions, making it easier
to find the definitions relevant to them. Programmers adding new functionality
to this code would know where to place the code to keep the program organized.
Earlier, we mentioned that *src/main.rs* and *src/lib.rs* are called crate
roots. The reason for their name is that the contents of either of these two
@ -158,14 +160,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,
`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 defined within `front_of_house`). To continue the
family metaphor, 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`.
This tree shows how some of the modules nest inside one another; 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`.
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

@ -1,30 +1,29 @@
## Paths for Referring to an Item in the Module Tree
To show Rust where to find an item in a module tree, we use a path in the same
way we use a path when navigating a filesystem. If we want to call a function,
we need to know its path.
way we use a path when navigating a filesystem. To call a function, we need to
know its path.
A path can take two forms:
* An *absolute path* starts from a crate root by using a crate name (for code
from an external crate) or a literal `crate` (for code from the current
crate).
* An *absolute path* is the full path starting from a crate root; for code
from an external crate, the absolute path begins with the crate name, and for
code from the current crate, it starts with the literal `crate`.
* A *relative path* starts from the current module and uses `self`, `super`, or
an identifier in the current module.
Both absolute and relative paths are followed by one or more identifiers
separated by double colons (`::`).
Lets return to the example in Listing 7-1. How do we call the
`add_to_waitlist` function? 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. 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` Keyword”][pub]<!-- ignore --> section, well go into more detail
about `pub`. Note that this example wont compile just yet; well explain why
in a bit.
Returning to Listing 7-1, say we want to call the `add_to_waitlist` function.
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. 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` Keyword”][pub]<!-- ignore
--> section, well go into more detail about `pub`. Note that this example
wont compile just yet; well explain why in a bit.
<span class="filename">Filename: src/lib.rs</span>
@ -38,33 +37,30 @@ absolute and relative paths</span>
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
crate as `eat_at_restaurant`, which means we can use the `crate` keyword to
start an absolute path.
After `crate`, we include each of the successive modules until we make our way
to `add_to_waitlist`. You can imagine a filesystem with the same structure, and
wed specify the path `/front_of_house/hosting/add_to_waitlist` to run the
`add_to_waitlist` program; using the `crate` name to start from the crate root
is like using `/` to start from the filesystem root in your shell.
start an absolute path. We then include each of the successive modules until we
make our way to `add_to_waitlist`. You can imagine a filesystem with the same
structure: wed specify the path `/front_of_house/hosting/add_to_waitlist` to
run the `add_to_waitlist` program; using the `crate` name to start from the
crate root is like using `/` to start from the filesystem root in your shell.
The second time we call `add_to_waitlist` in `eat_at_restaurant`, we use a
relative path. The path starts with `front_of_house`, the name of the module
defined at the same level of the module tree as `eat_at_restaurant`. Here the
filesystem equivalent would be using the path
`front_of_house/hosting/add_to_waitlist`. Starting with a name means that the
path is relative.
`front_of_house/hosting/add_to_waitlist`. Starting with a module name means
that the path is relative.
Choosing whether to use a relative or absolute path is a decision youll make
based on your project. The decision should depend 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 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 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.
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.
@ -79,28 +75,23 @@ Listing 7-3</span>
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`
function, but Rust wont let us use them because it doesnt have access to the
private sections.
private sections. In Rust, all items (functions, methods, structs, enums,
modules, and constants) are private to parent modules by default. If you want
to make an item like a function or struct private, you put it in a module.
Modules arent useful only for organizing your code. They also define Rusts
*privacy boundary*: the line that encapsulates the implementation details
external code isnt allowed to know about, call, or rely on. So, if you want to
make an item like a function or struct private, you put it in a module.
The way privacy works in Rust is that all items (functions, methods, structs,
enums, modules, and constants) are private by default. Items in a parent module
cant use the private items inside child modules, but items in child modules
can use the items in their ancestor modules. The reason is that child modules
wrap and hide their implementation details, but the child modules can see the
context in which theyre defined. To continue with the restaurant metaphor,
think of the privacy rules as being like the back office of a restaurant: what
goes on in there is private to restaurant customers, but office managers can
see and do everything in the restaurant in which they operate.
Items in a parent module cant use the private items inside child modules, but
items in child modules can use the items in their ancestor modules. This is
because child modules wrap and hide their implementation details, but the child
modules can see the context in which theyre defined. To continue with our
metaphor, think of the privacy rules as being like the back office of a
restaurant: what goes on in there is private to restaurant customers, but
office managers can see and do everything in the restaurant they operate.
Rust chose to have the module system function this way so that hiding inner
implementation details is the default. That way, you know which parts of the
inner code you can change without breaking outer code. But you can expose inner
parts of child modules code to outer ancestor modules by using the `pub`
keyword to make an item public.
inner code you can change without breaking outer code. However, Rust does give
you the option to expose inner parts of child modules code to outer ancestor
modules by using the `pub` keyword to make an item public.
### Exposing Paths with the `pub` Keyword
@ -132,7 +123,10 @@ 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
access `hosting`. But the *contents* of `hosting` are still private; making the
module public doesnt make its contents public. The `pub` keyword on a module
only lets code in its ancestor modules refer to it.
only lets code in its ancestor modules refer to it, not access its inner code.
Because modules are containers, theres not much we can do by only making the
module public; we need to go further and choose to make one or more of the
items within the module public as well.
The errors in Listing 7-6 say that the `add_to_waitlist` function is private.
The privacy rules apply to structs, enums, functions, and methods as well as
@ -151,19 +145,19 @@ keyword before its definition, as in Listing 7-7.
and `fn add_to_waitlist` lets us call the function from
`eat_at_restaurant`</span>
Now the code will compile! Lets look at the absolute and the relative path and
double-check why adding the `pub` keyword lets us use these paths in
`add_to_waitlist` with respect to the privacy rules.
Now the code will compile! To see why adding the `pub` keyword lets us use
these paths in `add_to_waitlist` with respect to the privacy rules, lets look
at the absolute and the relative paths.
In the absolute path, we start with `crate`, the root of our crates module
tree. Then the `front_of_house` module is defined in the crate root. The
`front_of_house` module isnt public, but because the `eat_at_restaurant`
function is defined in the same module as `front_of_house` (that is,
`eat_at_restaurant` and `front_of_house` are siblings), we can refer to
`front_of_house` from `eat_at_restaurant`. Next is the `hosting` module marked
with `pub`. We can access the parent module of `hosting`, so we can access
`hosting`. Finally, the `add_to_waitlist` function is marked with `pub` and we
can access its parent module, so this function call works!
tree. The `front_of_house` module is defined in the crate root. While
`front_of_house` isnt public, because the `eat_at_restaurant` function is
defined in the same module as `front_of_house` (that is, `eat_at_restaurant`
and `front_of_house` are siblings), we can refer to `front_of_house` from
`eat_at_restaurant`. Next is the `hosting` module marked with `pub`. We can
access the parent module of `hosting`, so we can access `hosting`. Finally, the
`add_to_waitlist` function is marked with `pub` and we can access its parent
module, so this function call works!
In the relative path, the logic is the same as the absolute path except for the
first step: rather than starting from the crate root, the path starts from
@ -174,21 +168,21 @@ as `eat_at_restaurant`, so the relative path starting from the module in which
function call is valid!
If you plan on sharing your library crate so other projects can use your code,
your public API is your contract with users of your crate about how they
interact with your code. There are many considerations around managing changes
to your public API to make it easier for people to depend on your crate. These
considerations are out of the scope of this book; if youre interested in this
topic, see [The Rust API Guidelines][api-guidelines].
your public API is your contract with users of your crate that determines how
they can interact with your code. There are many considerations around managing
changes to your public API to make it easier for people to depend on your
crate. These considerations are out of the scope of this book; if youre
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 will have just
> enough code in the binary crate to start an executable that calls code with
> the library crate. This lets other projects benefit from the most
> functionality that the package provides, because the library crates code can
> be shared.
> 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 with the library crate. This
> lets other projects benefit from the most 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.
@ -203,9 +197,12 @@ topic, see [The Rust API Guidelines][api-guidelines].
### Starting Relative Paths with `super`
We can also construct relative paths that begin in the parent module by using
`super` at the start of the path. This is like starting a filesystem path with
the `..` syntax. Why would we want to do this?
We can construct relative paths that begin in the parent module, rather than
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. This 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 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
@ -234,15 +231,15 @@ 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 extra details. 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 with a public `toast` field but a
private `seasonal_fruit` field. This models the case in a restaurant where the
customer can pick the type of bread that comes with a meal, but the chef
decides which fruit accompanies the meal based on whats in season and in
stock. The available fruit changes quickly, so customers cant choose the fruit
or even see which fruit theyll get.
few details extra 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
with a public `toast` field but a private `seasonal_fruit` field. This models
the case in a restaurant where the customer can pick the type of bread that
comes with a meal, but the chef decides which fruit accompanies the meal based
on whats in season and in stock. The available fruit changes quickly, so
customers cant choose the fruit or even see which fruit theyll get.
<span class="filename">Filename: src/lib.rs</span>
@ -279,11 +276,13 @@ only need the `pub` before the `enum` keyword, as shown in Listing 7-10.
variants public</span>
Because we made the `Appetizer` enum public, we can use the `Soup` and `Salad`
variants in `eat_at_restaurant`. Enums arent very useful unless their variants
are public; it would be annoying to have to annotate all enum variants with
`pub` in every case, so the default for enum variants is to be public. Structs
are often useful without their fields being public, so struct fields follow the
general rule of everything being private by default unless annotated with `pub`.
variants in `eat_at_restaurant`.
Enums arent very useful unless their variants are public; it would be annoying
to have to annotate all enum variants with `pub` in every case, so the default
for enum variants is to be public. Structs are often useful without their
fields being public, so struct fields follow the general rule of everything
being private by default unless annotated with `pub`.
Theres one more situation involving `pub` that we havent covered, and that is
our last module system feature: the `use` keyword. Well cover `use` by itself

View File

@ -1,12 +1,11 @@
## Bringing Paths into Scope with the `use` Keyword
It might seem like the paths weve written to call functions so far are
inconveniently long and repetitive. For example, in Listing 7-7, whether we
chose the absolute or relative path to the `add_to_waitlist` function, every
time we wanted to call `add_to_waitlist` we had to specify `front_of_house` and
`hosting` too. Fortunately, theres a way to simplify this process. We can
create a shortcut to a path with the `use` keyword once, and then use the
shorter name everywhere else in the scope.
Having to write out the paths to call functions can feel inconvenient and
repetitive. In Listing 7-7, whether we chose the absolute or relative path to
the `add_to_waitlist` function, every time we wanted to call `add_to_waitlist`
we had to specify `front_of_house` and `hosting` too. Fortunately, theres a
way to simplify this process: we can create a shortcut to a path with the `use`
keyword once, and then use the shorter name everywhere else in the scope.
In Listing 7-11, we bring the `crate::front_of_house::hosting` module into the
scope of the `eat_at_restaurant` function so we only have to specify
@ -31,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 and the function body wont compile:
statement, so the function body wont compile:
<span class="filename">Filename: src/lib.rs</span>
@ -118,8 +117,8 @@ meant when we used `Result`.
Theres another solution to the problem of bringing two types of the same name
into the same scope with `use`: after the path, we can specify `as` and a new
local name, or alias, for the type. Listing 7-16 shows another way to write the
code in Listing 7-15 by renaming one of the two `Result` types using `as`.
local name, or *alias*, for the type. Listing 7-16 shows another way to write
the code in Listing 7-15 by renaming one of the two `Result` types using `as`.
<span class="filename">Filename: src/lib.rs</span>
@ -211,7 +210,7 @@ Members of the Rust community have made many packages available at
involves these same steps: listing them in your packages *Cargo.toml* file and
using `use` to bring items from their crates into scope.
Note that the standard library (`std`) is also a crate thats external to our
Note that the standard `std` library is also a crate thats external to our
package. Because the standard library is shipped with the Rust language, we
dont need to change *Cargo.toml* to include `std`. But we do need to refer to
it with `use` to bring items from there into our packages scope. For example,
@ -287,7 +286,7 @@ This line brings `std::io` and `std::io::Write` into scope.
### The Glob Operator
If we want to bring *all* public items defined in a path into scope, we can
specify that path followed by `*`, the glob operator:
specify that path followed by the `*` glob operator:
```rust
use std::collections::*;

View File

@ -4,10 +4,11 @@ So far, all the examples in this chapter defined multiple modules in one file.
When modules get large, you might want to move their definitions to a separate
file to make the code easier to navigate.
For example, lets start from the code in Listing 7-17 and extract modules into
files instead of having all the 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*.
For example, lets start from the code in Listing 7-17 that had multiple
restaurant modules. Well extract modules into files instead of having all the
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
code inside the curly brackets for the `front_of_house` module, leaving only
@ -26,8 +27,8 @@ body will be in *src/front_of_house.rs*</span>
Next, place the code that was in the curly brackets into a new file named
*src/front_of_house.rs*, as shown in Listing 7-22. The compiler knows to look
in this file because of the module declaration it found in the crate root with
the name `front_of_house`.
in this file because it came across the module declaration in the crate root
with the name `front_of_house`.
<span class="filename">Filename: src/front_of_house.rs</span>
@ -38,19 +39,19 @@ the name `front_of_house`.
<span class="caption">Listing 7-22: Definitions inside the `front_of_house`
module in *src/front_of_house.rs*</span>
Note that you only need to load the contents of a file using a `mod`
declaration once somewhere in your module tree. Once the compiler knows the
file is part of the project (and knows where in the module tree the code
resides because of where youve put the `mod` statement), other files in your
project should refer to the code in that file using a path to where it was
declared as covered in the [“Paths for Referring to an Item in the Module
Tree”][paths]<!-- ignore --> section. In other words, `mod` is *not* an
“include” operation that other programming languages have.
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
where in the module tree the code resides because of where youve put the `mod`
statement), other files in your project should refer to the loaded files code
using a path to where it was declared, as covered in the [“Paths for Referring
to an Item in the Module Tree”][paths]<!-- ignore --> section. In other words,
`mod` is *not* an “include” operation that you may have seen in other
programming languages.
Next, well extract the `hosting` module to its own file as well. The process
is a bit different because `hosting` is a child module of `front_of_house`, not
of the root module. The file for `hosting` will be in a directory named for its
place in the module tree.
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/*.
To start moving `hosting`, we change *src/front_of_house.rs* to contain only the
declaration of the `hosting` module:
@ -61,9 +62,8 @@ 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
*src/front_of_house/hosting.rs* to contain the definitions made in the
`hosting` module:
Then we create a *src/front_of_house* directory and a file *hosting.rs* to
contain the definitions made in the `hosting` module:
<span class="filename">Filename: src/front_of_house/hosting.rs</span>
@ -72,40 +72,39 @@ Then we create a *src/front_of_house* directory and a file
```
If we instead put *hosting.rs* in the *src* directory, the compiler would
expect that code to be in a `hosting` module declared in the crate root, not as
a child of the `front_of_house` module. The rules the compiler follows to know
what files to look in for modules code means the directories and files more
closely match the module tree.
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
directories and files more closely match the module tree.
> ### Alternate File Paths
>
> This section covered the most idiomatic file paths the Rust compiler uses;
> but an older file path is also still supported.
>
> For a module named `front_of_house` declared in the crate root, the compiler
> will look for the modules code in:
> So far weve covered the most idiomatic file paths the Rust compiler uses,
> but Rust also supports an older style of file path. For a module named
> `front_of_house` declared in the crate root, the compiler will look for the
> modules code in:
>
> * *src/front_of_house.rs* (what we covered)
> * *src/front_of_house/mod.rs* (older, still supported path)
> * *src/front_of_house/mod.rs* (older style, still supported path)
>
> For a module named `hosting` that is a submodule of `front_of_house`, the
> compiler will look for the modules code in:
>
> * *src/front_of_house/hosting.rs* (what we covered)
> * *src/front_of_house/hosting/mod.rs* (older, still supported path)
> * *src/front_of_house/hosting/mod.rs* (older style, still supported path)
>
> If you use both for the same module, youll get a compiler error. Using
> different styles for different modules in the same project is allowed, but
> If you use both styles for the same module, youll get a compiler error. Using
> 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
> when you have them open in your editor at the same time.
Moving each modules code to a separate file is now complete, and the module
tree remains the same. The function calls in `eat_at_restaurant` will work
without any modification, even though the definitions live in different files.
This technique lets you move modules to new files as they grow in size.
Weve moved each modules code to a separate file, and the module tree remains
the same. The function calls in `eat_at_restaurant` will work without any
modification, even though the definitions live in different files. This
technique lets you move modules to new files as they grow in size.
Note that the `pub use crate::front_of_house::hosting` statement in
*src/lib.rs* also hasnt changed, nor does `use` have any impact on what files