mirror of https://github.com/rust-lang/book
Backport changes from print for ch7
This commit is contained in:
parent
d207d894cc
commit
98165c4279
|
@ -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 that’s a
|
||||
library or binary crate.
|
||||
|
||||
Let’s walk through what happens when we create a package. First, we enter the
|
||||
command `cargo new`:
|
||||
Let’s 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, there’s a *Cargo.toml* file, giving us a package. There’s also a
|
||||
*src* directory that contains *main.rs*. Open *Cargo.toml* in your text editor,
|
||||
and note there’s 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, there’s a *Cargo.toml* file, giving us a package.
|
||||
There’s also a *src* directory that contains *main.rs*. Open *Cargo.toml* in
|
||||
your text editor, and note there’s 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*
|
||||
|
|
|
@ -1,27 +1,23 @@
|
|||
## Defining Modules to Control Scope and Privacy
|
||||
|
||||
In this section, we’ll 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. We’ll also discuss
|
||||
the `as` keyword, external packages, and the glob operator.
|
||||
|
||||
First, we’re going to start with a list of rules for easy reference when you’re
|
||||
organizing your code in the future. Then we’ll 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. We’ll 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. We’ll 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 module’s code in these places:
|
||||
- Inline, within curly brackets that replace the semicolon following `mod
|
||||
garden`
|
||||
|
@ -40,7 +36,7 @@ for the module’s 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 module’s 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
|
||||
crate’s directory, also named `backyard`, contains these files and directories:
|
||||
Here, we create a binary crate named `backyard` that illustrates these rules.
|
||||
The crate’s directory, also named `backyard`, contains these files and
|
||||
directories:
|
||||
|
||||
```text
|
||||
backyard
|
||||
|
@ -93,7 +90,7 @@ Now let’s 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, let’s write a library crate that provides the functionality of a
|
||||
restaurant. We’ll 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. Here’s 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 they’re 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 they’re 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 filesystem’s directory tree on your
|
||||
computer; this is a very apt comparison! Just like directories in a filesystem,
|
||||
|
|
|
@ -20,10 +20,10 @@ This is the same as asking: what’s the path of the `add_to_waitlist` function?
|
|||
Listing 7-3 contains Listing 7-1 with some of the modules and functions
|
||||
removed.
|
||||
|
||||
We’ll 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
|
||||
We’ll 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
|
||||
there’s another problem remaining that will prevent this example from compiling
|
||||
as-is. We’ll explain why in a bit.
|
||||
as is. We’ll explain why in a bit.
|
||||
|
||||
The `eat_at_restaurant` function is part of our library crate’s 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 you’ll make
|
||||
based on your project, and depends on whether you’re 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`, we’d 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 it’s more likely we’ll want to move code
|
||||
definitions and item calls independently of each other.
|
||||
based on your project, and it depends on whether you’re 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`, we’d
|
||||
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 it’s
|
||||
more likely we’ll want to move code definitions and item calls independently of
|
||||
each other.
|
||||
|
||||
Let’s try to compile Listing 7-3 and find out why it won’t 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 crate’s 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 crate’s 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 struct’s fields
|
||||
will still be private. We can make each field public or not on a case-by-case
|
||||
basis. In Listing 7-9, we’ve 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 can’t 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
|
||||
|
|
|
@ -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 won’t compile:
|
||||
statement, so the function body won’t 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
|
||||
function’s 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 function’s 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 isn’t 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 we’re bringing two items with the same name
|
||||
into scope with `use` statements, because Rust doesn’t 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`, we’d
|
||||
have two `Result` types in the same scope and Rust wouldn’t know which one we
|
||||
have two `Result` types in the same scope, and Rust wouldn’t 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 code’s scope, we can combine `pub`
|
||||
and `use`. This technique is called *re-exporting* because we’re 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 we’re 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 we’re 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 we’re 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>
|
||||
|
||||
|
|
|
@ -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, we’ll extract the `front_of_house` module to its own file. Remove the
|
||||
First we’ll 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 won’t compile until we create the
|
||||
|
@ -51,10 +51,10 @@ programming languages.
|
|||
Next, we’ll 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. We’ll 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
|
||||
compiler’s rules for which files to check for which modules’ code means the
|
||||
compiler’s 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, you’ll 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, you’ll 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
|
||||
|
|
Loading…
Reference in New Issue