mirror of
https://github.com/rust-lang/book.git
synced 2026-09-14 00:34:47 -04:00
Forward porting the docx changes to nostarch md
This commit is contained in:
@@ -1,44 +1,47 @@
|
||||
|
||||
[TOC]
|
||||
|
||||
# Modules
|
||||
# Using Modules to Reuse and Organize Code
|
||||
|
||||
When you start writing programs in Rust, your code might live solely in the
|
||||
`main` function. As your code grows, you’ll eventually move functionality out
|
||||
into other functions, both for re-use and for better organization. By splitting
|
||||
your code up into smaller chunks, each chunk is easier to understand on its
|
||||
own. But what happens if you find yourself with too many functions? Rust has a
|
||||
module system that handles the problem of wanting to re-use code while keeping
|
||||
your code organized.
|
||||
`main` function. As your code grows, you’ll eventually move functionality into
|
||||
other functions for reuse and better organization. By splitting your code into
|
||||
smaller chunks, each chunk is easier to understand on its own. But what happens
|
||||
if you have too many functions? Rust has a module system that enables the reuse
|
||||
of code in an organized fashion.
|
||||
|
||||
In the same way that you extract lines of code into a function, you can extract
|
||||
functions (and other code like structs and enums too) into different modules. A
|
||||
functions (and other code, like structs and enums) into different modules. A
|
||||
*module* is a namespace that contains definitions of functions or types, and
|
||||
you can choose whether those definitions are visible outside their module
|
||||
(public) or not (private). Here’s an overview of how modules work:
|
||||
|
||||
* You declare a new module with the keyword `mod`
|
||||
* By default, everything is set as private (including modules). You can use the
|
||||
`pub` keyword to make a module public and therefore visible outside of its
|
||||
* You declare a new module using the keyword `mod`.
|
||||
* By default, functions, types, constants, and modules are private. You can use
|
||||
the `pub` keyword to make an item public and therefore visible outside its
|
||||
namespace.
|
||||
* The `use` keyword allows you to bring modules, or the definitions inside
|
||||
modules, into scope so that it’s easier to refer to them.
|
||||
modules, into scope so it’s easier to refer to them.
|
||||
|
||||
We’ll take a look at each of these parts and see how they fit into the whole.
|
||||
We’ll look at each of these parts to see how they fit into the whole.
|
||||
|
||||
## `mod` and the Filesystem
|
||||
|
||||
We’ll start our module example by making a new project with Cargo, but instead
|
||||
of creating a binary crate, we’re going to make a library crate: a project that
|
||||
other people can pull into their projects as a dependency. We saw this with the
|
||||
`rand` crate in Chapter 2.
|
||||
of creating a binary crate, we’ll make a library crate: a project that other
|
||||
people can pull into their projects as a dependency. For example, the `rand`
|
||||
crate in Chapter 2 is a library crate that we used as a dependency in the
|
||||
guessing game project.
|
||||
|
||||
Prod: Check xref
|
||||
|
||||
We’ll create a skeleton of a library that provides some general networking
|
||||
functionality; we’re going to concentrate on the organization of the modules
|
||||
and functions, but not worry about what code goes in the function bodies. We’ll
|
||||
call our library `communicator`. By default, cargo will create a library unless
|
||||
another type of project is specified, so if we leave off the `--bin` option
|
||||
that we’ve been using so far our project will be a library:
|
||||
functionality; we’ll concentrate on the organization of the modules and
|
||||
functions but we won’t worry about what code goes in the function bodies. We’ll
|
||||
call our library `communicator`. By default, Cargo will create a library unless
|
||||
another type of project is specified: if we omit the `--bin` option that we’ve
|
||||
been using in all of the chapters preceding this one, our project will be a
|
||||
library:
|
||||
|
||||
```
|
||||
$ cargo new communicator
|
||||
@@ -46,7 +49,7 @@ $ cd communicator
|
||||
```
|
||||
|
||||
Notice that Cargo generated *src/lib.rs* instead of *src/main.rs*. Inside
|
||||
*src/lib.rs* we’ll find this:
|
||||
*src/lib.rs* we’ll find the following:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -60,24 +63,26 @@ mod tests {
|
||||
```
|
||||
|
||||
Cargo creates an empty test to help us get our library started, rather than the
|
||||
“Hello, world!” binary that we get with the `--bin` option. We’ll look at the
|
||||
`#[]` and `mod tests` syntax a little later, but for now just make sure to
|
||||
leave it in your *src/lib.rs*.
|
||||
“Hello, world!” binary that we get when we use the `--bin` option. We’ll look
|
||||
at the `#[]` and `mod tests` syntax in the “Using `super` to Access a Parent
|
||||
Module” section later in this chapter, but for now, leave this code at the
|
||||
bottom of *src/lib.rs*.
|
||||
|
||||
Since we don’t have a *src/main.rs*, there’s nothing for Cargo to execute with
|
||||
the `cargo run` command. Therefore, we will be using the `cargo build` command
|
||||
to only compile our library crate’s code.
|
||||
Prod: Check xref
|
||||
|
||||
We’re going to look at different options for organizing your library’s code
|
||||
which will be suitable in a variety of situations, depending on the intentions
|
||||
you have for your code.
|
||||
Because we don’t have a *src/main.rs* file, there’s nothing for Cargo to
|
||||
execute with the `cargo run` command. Therefore, we’ll use the `cargo build`
|
||||
command to compile our library crate’s code.
|
||||
|
||||
We’ll look at different options for organizing your library’s code that will be
|
||||
suitable in a variety of situations, depending on the intent of the code.
|
||||
|
||||
### Module Definitions
|
||||
|
||||
For our `communicator` networking library, we’re first going to define a module
|
||||
named `network` that contains the definition of a function called `connect`.
|
||||
Every module definition in Rust starts with the `mod` keyword. Add this code to
|
||||
the beginning of the *src/lib.rs* file, above the test code:
|
||||
For our `communicator` networking library, we’ll first define a module named
|
||||
`network` that contains the definition of a function called `connect`. Every
|
||||
module definition in Rust starts with the `mod` keyword. Add this code to the
|
||||
beginning of the *src/lib.rs* file, above the test code:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -88,16 +93,16 @@ mod network {
|
||||
}
|
||||
```
|
||||
|
||||
After the `mod` keyword, we put the name of the module, `network`, then a block
|
||||
of code in curly braces. Everything inside this block is inside the namespace
|
||||
`network`. In this case, we have a single function, `connect`. If we wanted to
|
||||
call this function from a script outside the `network` module, we would need to
|
||||
specify the module and use the namespace syntax `::`, like so:
|
||||
`network::connect()`, rather than just `connect()`.
|
||||
After the `mod` keyword, we put the name of the module, `network`, and then a
|
||||
block of code in curly braces. Everything inside this block is inside the
|
||||
namespace `network`. In this case, we have a single function, `connect`. If we
|
||||
wanted to call this function from a script outside the `network` module, we
|
||||
would need to specify the module and use the namespace syntax `::`, like so:
|
||||
`network::connect()` rather than just `connect()`.
|
||||
|
||||
We can also have multiple modules, side-by-side, in the same *src/lib.rs* file.
|
||||
For example, to have a `client` module too, that also has a function named
|
||||
`connect`, we can add it as shown in Listing 7-1:
|
||||
We can also have multiple modules, side by side, in the same *src/lib.rs* file.
|
||||
For example, to also have a `client` module that has a function named `connect`
|
||||
as well, we can add it as shown in Listing 7-1:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -113,22 +118,24 @@ mod client {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-1: The `network` module and the `client` module
|
||||
defined side-by-side in *src/lib.rs*
|
||||
Listing 7-1: The `network` module and the `client` module defined side by side
|
||||
in *src/lib.rs*
|
||||
|
||||
Now we have a `network::connect` function and a `client::connect` function.
|
||||
These can have completely different functionality, and the function names do
|
||||
not conflict with each other since they’re in different modules.
|
||||
not conflict with each other because they’re in different modules.
|
||||
|
||||
While in this case we’re building a library, there's nothing special about
|
||||
*src/lib.rs*. We could also make use of submodules in *src/main.rs* as well. In
|
||||
fact, we can also put modules inside of modules. This can be useful as your
|
||||
modules grow to keep related functionality organized together and separate
|
||||
functionality apart. The choice of how you organize your code depends on how
|
||||
you think about the relationship between the parts of your code. For instance,
|
||||
the `client` code and its `connect` function might make more sense to users of
|
||||
our library if it was inside the `network` namespace instead, like in Listing
|
||||
7-2:
|
||||
In this case, because we’re building a library, so the file that serves as the
|
||||
entry point for building our library is *src/lib.rs*. However, in respect to
|
||||
creating modules, there’s nothing special about *src/lib.rs*. We could also
|
||||
create modules in *src/main.rs* for a binary crate in the same way as we're
|
||||
creating modules in *src/lib.rs* for our example library crate. In fact, we can
|
||||
put modules inside of modules, which can be useful as your modules grow to keep
|
||||
related functionality organized together and separate functionality apart. The
|
||||
choice of how you organize your code depends on how you think about the
|
||||
relationship between the parts of your code. For instance, the `client` code
|
||||
and its `connect` function might make more sense to users of our library if
|
||||
they were inside the `network` namespace instead, as in Listing 7-2:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -144,19 +151,18 @@ mod network {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-2: Moving the `client` module inside of the
|
||||
`network` module
|
||||
Listing 7-2: Moving the `client` module inside the `network` module
|
||||
|
||||
In your *src/lib.rs* file, replace the existing `mod network` and `mod client`
|
||||
definitions with this one that has the `client` module as an inner module of
|
||||
`network`. Now we have the functions `network::connect` and
|
||||
definitions with the ones in Listing 7-2, which have the `client` module as an
|
||||
inner module of `network`. Now we have the functions `network::connect` and
|
||||
`network::client::connect`: again, the two functions named `connect` don’t
|
||||
conflict with each other since they’re in different namespaces.
|
||||
conflict with each other because they’re in different namespaces.
|
||||
|
||||
In this way, modules form a hierarchy. The contents of *src/lib.rs* are at the
|
||||
topmost level, and the submodules are at lower levels. Here’s what the
|
||||
organization of our example from Listing 7-1 looks like when thought of this
|
||||
way:
|
||||
organization of our example in Listing 7-1 looks like when thought of as a
|
||||
hierarchy:
|
||||
|
||||
```
|
||||
communicator
|
||||
@@ -164,7 +170,7 @@ communicator
|
||||
└── client
|
||||
```
|
||||
|
||||
And here’s the example from Listing 7-2:
|
||||
And here’s the hierarchy corresponding to the example in Listing 7-2:
|
||||
|
||||
```
|
||||
communicator
|
||||
@@ -172,20 +178,21 @@ communicator
|
||||
└── client
|
||||
```
|
||||
|
||||
You can see that in Listing 7-2, `client` is a child of the `network` module,
|
||||
rather than a sibling. More complicated projects can have a lot of modules, and
|
||||
they’ll need to be organized logically in order to keep track of them. What
|
||||
“logically” means in your project is up to you and depends on how you and users
|
||||
of your library think about your project’s domain. Use the techniques we’ve
|
||||
shown here to create side-by-side modules and nested modules in whatever
|
||||
structure you would like.
|
||||
The hierarchy shows that in Listing 7-2, `client` is a child of the `network`
|
||||
module rather than a sibling. More complicated projects can have many modules,
|
||||
and they’ll need to be organized logically in order to keep track of them. What
|
||||
“logically” means in your project is up to you and depends on how you and your
|
||||
library’s users think about your project’s domain. Use the techniques shown
|
||||
here to create side-by-side modules and nested modules in whatever structure
|
||||
you would like.
|
||||
|
||||
### Moving Modules to Other Files
|
||||
|
||||
Modules form a hierarchical structure, much like another structure in computing
|
||||
that you’re used to: file systems! We can use Rust’s module system along with
|
||||
multiple files to split Rust projects up so that not everything lives in
|
||||
*src/lib.rs*. For this example, we will start with the code in Listing 7-3:
|
||||
that you’re used to: filesystems! We can use Rust’s module system along with
|
||||
multiple files to split up Rust projects so not everything lives in
|
||||
*src/lib.rs* or *src/main.rs*. For this example, let’s start with the code in
|
||||
Listing 7-3:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -206,10 +213,10 @@ mod network {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-3: Three modules, `client`, `network`, and
|
||||
`network::server`, all defined in *src/lib.rs*
|
||||
Listing 7-3: Three modules, `client`, `network`, and `network::server`, all
|
||||
defined in *src/lib.rs*
|
||||
|
||||
Which has this module hierarchy:
|
||||
The file *src/lib.rs* has this module hierarchy:
|
||||
|
||||
```
|
||||
communicator
|
||||
@@ -218,12 +225,12 @@ communicator
|
||||
└── server
|
||||
```
|
||||
|
||||
If these modules had many functions, and those functions were getting long, it
|
||||
would be difficult to scroll through this file to find the code we wanted to
|
||||
If these modules had many functions, and those functions were becoming lengthy,
|
||||
it would be difficult to scroll through this file to find the code we wanted to
|
||||
work with. Because the functions are nested inside one or more mod blocks, the
|
||||
lines of code inside the functions will start getting long as well. These would
|
||||
be good reasons to pull each of the `client`, `network`, and `server` modules
|
||||
out of *src/lib.rs* and into their own files.
|
||||
lines of code inside the functions will start getting lengthy as well. These
|
||||
would be good reasons to separate the `client`, `network`, and `server` modules
|
||||
from *src/lib.rs* and place them into their own files.
|
||||
|
||||
Let’s start by extracting the `client` module into another file. First, replace
|
||||
the `client` module code in *src/lib.rs* with the following:
|
||||
@@ -246,11 +253,11 @@ mod network {
|
||||
|
||||
We’re still *defining* the `client` module here, but by removing the curly
|
||||
braces and definitions inside the `client` module and replacing them with a
|
||||
semicolon, we’re letting Rust know to look in another location for the code
|
||||
defined inside that module.
|
||||
semicolon, we’re telling Rust to look in another location for the code defined
|
||||
inside that module.
|
||||
|
||||
So now we need to create the external file with that module name. Create a
|
||||
*client.rs* file in your *src/* directory, then open it up and enter the
|
||||
Now we need to create the external file with that module name. Create a
|
||||
*client.rs* file in your *src/* directory and open it. Then enter the
|
||||
following, which is the `connect` function in the `client` module that we
|
||||
removed in the previous step:
|
||||
|
||||
@@ -261,8 +268,8 @@ fn connect() {
|
||||
}
|
||||
```
|
||||
|
||||
Note that we don’t need a `mod` declaration in this file; that’s because we
|
||||
already declared the `client` module with `mod` in *src/lib.rs*. This file just
|
||||
Note that we don’t need a `mod` declaration in this file because we already
|
||||
declared the `client` module with `mod` in *src/lib.rs*. This file just
|
||||
provides the *contents* of the `client` module. If we put a `mod client` here,
|
||||
we’d be giving the `client` module its own submodule named `client`!
|
||||
|
||||
@@ -271,9 +278,9 @@ files to our project, we need to tell Rust in *src/lib.rs* to look in other
|
||||
files; this is why `mod client` needs to be defined in *src/lib.rs* and can’t
|
||||
be defined in *src/client.rs*.
|
||||
|
||||
Now, everything should compile successfully, though you’ll get a few warnings.
|
||||
Remember to use `cargo build` instead of `cargo run` since we have a library
|
||||
crate rather than a binary crate:
|
||||
Now the project should compile successfully, although you’ll get a few
|
||||
warnings. Remember to use `cargo build` instead of `cargo run` because we have
|
||||
a library crate rather than a binary crate:
|
||||
|
||||
```
|
||||
$ cargo build
|
||||
@@ -299,10 +306,13 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
```
|
||||
|
||||
These warnings tell us that we have functions that are never used. Don’t worry
|
||||
about those warnings for now; we’ll address them later in the chapter. The good
|
||||
news is that they’re just warnings; our project was built successfully!
|
||||
about these warnings for now; we’ll address them in the “Controlling Visibility
|
||||
with `pub`” section later in this chapter. The good news is that they’re just
|
||||
warnings; our project built successfully!
|
||||
|
||||
Let’s extract the `network` module into its own file next, using the same
|
||||
Prod: Check xref
|
||||
|
||||
Next, let’s extract the `network` module into its own file using the same
|
||||
pattern. In *src/lib.rs*, delete the body of the `network` module and add a
|
||||
semicolon to the declaration, like so:
|
||||
|
||||
@@ -329,14 +339,13 @@ mod server {
|
||||
```
|
||||
|
||||
Notice that we still have a `mod` declaration within this module file; this is
|
||||
because we still want `server` to be a sub-module of `network`.
|
||||
because we still want `server` to be a submodule of `network`.
|
||||
|
||||
Now run `cargo build` again. Success! We have one more module to extract:
|
||||
`server`. Because it’s a sub-module—that is, a module within a module—our
|
||||
current tactic of extracting a module into a file named after that module won’t
|
||||
work. We’re going to try anyway so that we can see the error. First change
|
||||
*src/network.rs* to have `mod server;` instead of the `server` module’s
|
||||
contents:
|
||||
Run `cargo build` again. Success! We have one more module to extract: `server`.
|
||||
Because it’s a submodule—that is, a module within a module—our current tactic
|
||||
of extracting a module into a file named after that module won’t work. We’ll
|
||||
try anyway so you can see the error. First, change *src/network.rs* to have
|
||||
`mod server;` instead of the `server` module’s contents:
|
||||
|
||||
Filename: src/network.rs
|
||||
|
||||
@@ -380,27 +389,28 @@ note: ... or maybe `use` the module `server` instead of possibly redeclaring it
|
||||
| ^^^^^^
|
||||
```
|
||||
|
||||
Listing 7-4: Error when trying to extract the `server`
|
||||
submodule into *src/server.rs*
|
||||
Listing 7-4: Error when trying to extract the `server` submodule into
|
||||
*src/server.rs*
|
||||
|
||||
The error says we `cannot declare a new module at this location` and is
|
||||
pointing to the `mod server;` line in *src/network.rs*. So *src/network.rs* is
|
||||
different than *src/lib.rs* somehow; let’s keep reading to understand why.
|
||||
different than *src/lib.rs* somehow: keep reading to understand why.
|
||||
|
||||
The note in the middle of Listing 7-4 is actually pretty helpful, as it points
|
||||
out something we haven’t yet talked about doing:
|
||||
The note in the middle of Listing 7-4 is actually very helpful because it
|
||||
points out something we haven’t yet talked about doing:
|
||||
|
||||
```
|
||||
note: maybe move this module `network` to its own directory via `network/mod.rs`
|
||||
note: maybe move this module `network` to its own directory via
|
||||
`network/mod.rs`
|
||||
```
|
||||
|
||||
Instead of continuing to follow the same file naming pattern we used
|
||||
previously, we can do what the note suggests:
|
||||
|
||||
1. Make a new *directory* named *network*, the parent module’s name
|
||||
2. Move the *src/network.rs* file into the new *network* directory and rename
|
||||
it so that it is now *src/network/mod.rs*
|
||||
3. Move the submodule file *src/server.rs* into the *network* directory
|
||||
1. Make a new *directory* named *network*, the parent module’s name.
|
||||
2. Move the *src/network.rs* file into the new *network* directory, and
|
||||
rename *src/network/mod.rs*.
|
||||
3. Move the submodule file *src/server.rs* into the *network* directory.
|
||||
|
||||
Here are commands to carry out these steps:
|
||||
|
||||
@@ -410,7 +420,7 @@ $ mv src/network.rs src/network/mod.rs
|
||||
$ mv src/server.rs src/network
|
||||
```
|
||||
|
||||
Now if we try to `cargo build`, compilation will work (we’ll still have
|
||||
Now when we try to run `cargo build`, compilation will work (we’ll still have
|
||||
warnings though). Our module layout still looks like this, which is exactly the
|
||||
same as it did when we had all the code in *src/lib.rs* in Listing 7-3:
|
||||
|
||||
@@ -425,22 +435,22 @@ The corresponding file layout now looks like this:
|
||||
|
||||
```
|
||||
├── src
|
||||
│ ├── client.rs
|
||||
│ ├── lib.rs
|
||||
│ └── network
|
||||
│ ├── mod.rs
|
||||
│ └── server.rs
|
||||
│ ├── client.rs
|
||||
│ ├── lib.rs
|
||||
│ └── network
|
||||
│ ├── mod.rs
|
||||
│ └── server.rs
|
||||
```
|
||||
|
||||
So when we wanted to extract the `network::server` module, why did we have to
|
||||
also change the *src/network.rs* file into the *src/network/mod.rs* file, and
|
||||
put the code for `network::server` in the *network* directory in
|
||||
*src/network/server.rs*, instead of just being able to extract the
|
||||
also change the *src/network.rs* file to the *src/network/mod.rs* file and put
|
||||
the code for `network::server` in the *network* directory in
|
||||
*src/network/server.rs* instead of just being able to extract the
|
||||
`network::server` module into *src/server.rs*? The reason is that Rust wouldn’t
|
||||
be able to tell that `server` was supposed to be a submodule of `network` if
|
||||
the *server.rs* file was in the *src* directory. To make it clearer why Rust
|
||||
can’t tell, let’s consider a different example with the following module
|
||||
hierarchy, where all the definitions are in *src/lib.rs*:
|
||||
be able to recognize that `server` was supposed to be a submodule of `network`
|
||||
if the *server.rs* file was in the *src* directory. To clarify Rust’s behavior
|
||||
here, let’s consider a different example with the following module hierarchy,
|
||||
where all the definitions are in *src/lib.rs*:
|
||||
|
||||
```
|
||||
communicator
|
||||
@@ -449,54 +459,54 @@ communicator
|
||||
└── client
|
||||
```
|
||||
|
||||
In this example, we have three modules again, `client`, `network`, and
|
||||
`network::client`. If we follow the same steps we originally did above for
|
||||
extracting modules into files, for the `client` module we would create
|
||||
*src/client.rs*. For the `network` module, we would create *src/network.rs*.
|
||||
Then we wouldn’t be able to extract the `network::client` module into a
|
||||
*src/client.rs* file, because that already exists for the top-level `client`
|
||||
module! If we put the code in both the `client` and `network::client` modules
|
||||
in the *src/client.rs* file, Rust would not have any way to know whether the
|
||||
code was for `client` or for `network::client`.
|
||||
In this example, we have three modules again: `client`, `network`, and
|
||||
`network::client`. Following the same steps we did earlier for extracting
|
||||
modules into files, we would create *src/client.rs* for the `client` module.
|
||||
For the `network` module, we would create *src/network.rs*. But we wouldn’t be
|
||||
able to extract the `network::client` module into a *src/client.rs* file
|
||||
because that already exists for the top-level `client` module! If we could put
|
||||
the code for *both* the `client` and `network::client` modules in the
|
||||
*src/client.rs* file, Rust wouldn’t have any way to know whether the code was
|
||||
for `client` or for `network::client`.
|
||||
|
||||
Therefore, once we wanted to extract a file for the `network::client` submodule
|
||||
of the `network` module, we needed to create a directory for the `network`
|
||||
module instead of a *src/network.rs* file. The code that is in the `network`
|
||||
module then goes into the *src/network/mod.rs* file, and the submodule
|
||||
Therefore, in order to extract a file for the `network::client` submodule of
|
||||
the `network` module, we needed to create a directory for the `network` module
|
||||
instead of a *src/network.rs* file. The code that is in the `network` module
|
||||
then goes into the *src/network/mod.rs* file, and the submodule
|
||||
`network::client` can have its own *src/network/client.rs* file. Now the
|
||||
top-level *src/client.rs* is unambiguously the code that belongs to the
|
||||
`client` module.
|
||||
|
||||
### Rules of Module File Systems
|
||||
### Rules of Module Filesystems
|
||||
|
||||
In summary, these are the rules of modules with regards to files:
|
||||
Let’s summarize the rules of modules with regard to files:
|
||||
|
||||
* If a module named `foo` has no submodules, you should put the declarations
|
||||
for `foo` in a file named *foo.rs*.
|
||||
* If a module named `foo` does have submodules, you should put the declarations
|
||||
for `foo` in a file named *foo/mod.rs*.
|
||||
|
||||
These rules apply recursively, so that if a module named `foo` has a submodule
|
||||
named `bar` and `bar` does not have submodules, you should have the following
|
||||
files in your *src* directory:
|
||||
These rules apply recursively, so if a module named `foo` has a submodule named
|
||||
`bar` and `bar` does not have submodules, you should have the following files
|
||||
in your *src* directory:
|
||||
|
||||
```
|
||||
├── foo
|
||||
│ ├── bar.rs (contains the declarations in `foo::bar`)
|
||||
│ └── mod.rs (contains the declarations in `foo`, including `mod bar`)
|
||||
│ ├── bar.rs (contains the declarations in `foo::bar`)
|
||||
│ └── mod.rs (contains the declarations in `foo`, including `mod bar`)
|
||||
```
|
||||
|
||||
The modules themselves should be declared in their parent module’s file using
|
||||
the `mod` keyword.
|
||||
The modules should be declared in their parent module’s file using the `mod`
|
||||
keyword.
|
||||
|
||||
Next, we’ll talk about the `pub` keyword, and get rid of those warnings!
|
||||
Next, we’ll talk about the `pub` keyword and get rid of those warnings!
|
||||
|
||||
## Controlling Visibility with `pub`
|
||||
|
||||
We resolved the error messages shown in Listing 7-4 by moving the `network` and
|
||||
`network::server` code into the *src/network/mod.rs* and
|
||||
*src/network/server.rs* files, respectively. At that point, `cargo build` was
|
||||
able to build our project, but we still get some warning messages about the
|
||||
able to build our project, but we still get warning messages about the
|
||||
`client::connect`, `network::connect`, and `network::server::connect` functions
|
||||
not being used:
|
||||
|
||||
@@ -521,15 +531,15 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
```
|
||||
|
||||
So why are we receiving these warnings? After all, we’re building a library
|
||||
with functions that are intended to be used by our *users*, and not necessarily
|
||||
by us within our own project, so it shouldn’t matter that these `connect`
|
||||
with functions that are intended to be used by our *users*, not necessarily by
|
||||
us within our own project, so it shouldn’t matter that these `connect`
|
||||
functions go unused. The point of creating them is that they will be used by
|
||||
another project and not our own.
|
||||
another project, not our own.
|
||||
|
||||
To understand why this program invokes these warnings, let’s try using the
|
||||
`connect` library as if we were another project, calling it externally. To do
|
||||
that, we’ll create a binary crate in the same directory as our library crate,
|
||||
by making a *src/main.rs* file containing this code:
|
||||
`connect` library from another project, calling it externally. To do that,
|
||||
we’ll create a binary crate in the same directory as our library crate by
|
||||
making a *src/main.rs* file containing this code:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -542,25 +552,25 @@ fn main() {
|
||||
```
|
||||
|
||||
We use the `extern crate` command to bring the `communicator` library crate
|
||||
into scope, because our package actually now contains *two* crates. Cargo
|
||||
treats *src/main.rs* as the root file of a binary crate, which is separate from
|
||||
the existing library crate whose root file is *src/lib.rs*. This pattern is
|
||||
quite common for executable projects: most functionality is in a library crate,
|
||||
and the binary crate uses that library crate. This way, other programs can also
|
||||
use the library crate, and it’s a nice separation of concerns.
|
||||
into scope. Our package now contains *two* crates. Cargo treats *src/main.rs*
|
||||
as the root file of a binary crate, which is separate from the existing library
|
||||
crate whose root file is *src/lib.rs*. This pattern is quite common for
|
||||
executable projects: most functionality is in a library crate, and the binary
|
||||
crate uses that library crate. As a result, other programs can also use the
|
||||
library crate, and it’s a nice separation of concerns.
|
||||
|
||||
From the point of view of a crate outside of the `communicator` library looking
|
||||
in, all of the modules we've been creating are within a module that has the
|
||||
same name as the crate, `communicator`. We call the top-level module of a crate
|
||||
the *root module*.
|
||||
From the point of view of a crate outside the `communicator` library looking
|
||||
in, all the modules we’ve been creating are within a module that has the same
|
||||
name as the crate, `communicator`. We call the top-level module of a crate the
|
||||
*root module*.
|
||||
|
||||
Also note that even if we're using an external crate within a submodule of our
|
||||
Also note that even if we’re using an external crate within a submodule of our
|
||||
project, the `extern crate` should go in our root module (so in *src/main.rs*
|
||||
or *src/lib.rs*). Then, in our submodules, we can refer to items from external
|
||||
crates as if the items are top-level modules.
|
||||
|
||||
Our binary crate right now just calls our library’s `connect` function from the
|
||||
`client` module. However, invoking `cargo build` will now give us an error
|
||||
Right now, our binary crate just calls our library’s `connect` function from
|
||||
the `client` module. However, invoking `cargo build` will now give us an error
|
||||
after the warnings:
|
||||
|
||||
```
|
||||
@@ -571,28 +581,29 @@ error: module `client` is private
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
Ah ha! This tells us that the `client` module is private, and this is the crux
|
||||
of the warnings. It’s also the first time we’ve run into the concepts of
|
||||
Ah ha! This error tells us that the `client` module is private, which is the
|
||||
crux of the warnings. It’s also the first time we’ve run into the concepts of
|
||||
*public* and *private* in the context of Rust. The default state of all code in
|
||||
Rust is private: no one else is allowed to use the code. If you don’t use a
|
||||
private function within your own program, since your own program is the only
|
||||
code allowed to use that function, Rust will warn you that the function has
|
||||
gone unused.
|
||||
private function within your program, because your program is the only code
|
||||
allowed to use that function, Rust will warn you that the function has gone
|
||||
unused.
|
||||
|
||||
Once we specify that a function like `client::connect` is public, not only will
|
||||
our call to that function from our binary crate be allowed, the warning that
|
||||
the function is unused will go away. Marking something public lets Rust know
|
||||
that we intend for the function to be used by code outside of our program. Rust
|
||||
considers the theoretical external usage that’s now possible as the function
|
||||
“being used.” Thus, when something is marked as public, Rust will not require
|
||||
that it’s used in our own program and will stop warning that the item is unused.
|
||||
After we specify that a function like `client::connect` is public, not only
|
||||
will our call to that function from our binary crate be allowed, but the
|
||||
warning that the function is unused will go away. Marking a function as public
|
||||
lets Rust know that the function will be used by code outside of our program.
|
||||
Rust considers the theoretical external usage that’s now possible as the
|
||||
function “being used.” Thus, when something is marked public, Rust will not
|
||||
require that it be used in our program and will stop warning that the item is
|
||||
unused.
|
||||
|
||||
### Making a Function Public
|
||||
|
||||
To tell Rust to make something public, we add the `pub` keyword to the start of
|
||||
the declaration of the item we want to make public. We’ll focus on fixing the
|
||||
warning that tells us that `client::connect` has gone unused for now, as well
|
||||
as the “module `client` is private” error from our binary crate. Modify
|
||||
warning that indicates `client::connect` has gone unused for now, as well as
|
||||
the `` module `client` is private `` error from our binary crate. Modify
|
||||
*src/lib.rs* to make the `client` module public, like so:
|
||||
|
||||
Filename: src/lib.rs
|
||||
@@ -603,7 +614,7 @@ pub mod client;
|
||||
mod network;
|
||||
```
|
||||
|
||||
The `pub` goes right before `mod`. Let’s try building again:
|
||||
The `pub` keyword is placed right before `mod`. Let’s try building again:
|
||||
|
||||
```
|
||||
error: function `connect` is private
|
||||
@@ -614,7 +625,7 @@ error: function `connect` is private
|
||||
```
|
||||
|
||||
Hooray! We have a different error! Yes, different error messages are a cause
|
||||
for celebration. The new error says “function `connect` is private”, so let’s
|
||||
for celebration. The new error shows `` function `connect` is private ``, so let’s
|
||||
edit *src/client.rs* to make `client::connect` public too:
|
||||
|
||||
Filename: src/client.rs
|
||||
@@ -624,7 +635,7 @@ pub fn connect() {
|
||||
}
|
||||
```
|
||||
|
||||
And run `cargo build` again:
|
||||
Now run `cargo build` again:
|
||||
|
||||
```
|
||||
warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
@@ -640,18 +651,19 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
| ^
|
||||
```
|
||||
|
||||
It compiled, and the warning about `client::connect` not being used is gone!
|
||||
The code compiled, and the warning about `client::connect` not being used is
|
||||
gone!
|
||||
|
||||
Unused code warnings don’t always indicate that something needs to be made
|
||||
public: if you *didn’t* want these functions to be part of your public API,
|
||||
unused code warnings could be alerting you to code you no longer needed and can
|
||||
safely delete. They could also be alerting you to a bug, if you had just
|
||||
Unused code warnings don’t always indicate that an item in your code needs to
|
||||
be made public: if you *didn’t* want these functions to be part of your public
|
||||
API, unused code warnings could be alerting you to code you no longer need that
|
||||
you can safely delete. They could also be alerting you to a bug if you had just
|
||||
accidentally removed all places within your library where this function is
|
||||
called.
|
||||
|
||||
In our case though, we *do* want the other two functions to be part of our
|
||||
crate’s public API, so let’s mark them as `pub` as well to try to get rid of
|
||||
the remaining warnings. Modify *src/network/mod.rs* to be:
|
||||
But in this case, we *do* want the other two functions to be part of our
|
||||
crate’s public API, so let’s mark them as `pub` as well to get rid of the
|
||||
remaining warnings. Modify *src/network/mod.rs* to look like the following:
|
||||
|
||||
Filename: src/network/mod.rs
|
||||
|
||||
@@ -662,7 +674,7 @@ pub fn connect() {
|
||||
mod server;
|
||||
```
|
||||
|
||||
And compile:
|
||||
Then compile the code:
|
||||
|
||||
```
|
||||
warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
@@ -678,12 +690,12 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
| ^
|
||||
```
|
||||
|
||||
Hmmm, we’re still getting an unused function warning even though
|
||||
`network::connect` is set to `pub`. This is because the function is public
|
||||
Hmmm, we’re still getting an unused function warning, even though
|
||||
`network::connect` is set to `pub`. The reason is that the function is public
|
||||
within the module, but the `network` module that the function resides in is not
|
||||
public. We’re working from the interior of the library out this time, where
|
||||
public. We’re working from the interior of the library out this time, whereas
|
||||
with `client::connect` we worked from the outside in. We need to change
|
||||
*src/lib.rs* to make `network` public too:
|
||||
*src/lib.rs* to make `network` public too, like so:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -693,7 +705,7 @@ pub mod client;
|
||||
pub mod network;
|
||||
```
|
||||
|
||||
Now if we compile, that warning is gone:
|
||||
Now when we compile, that warning is gone:
|
||||
|
||||
```
|
||||
warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
@@ -703,20 +715,21 @@ warning: function is never used: `connect`, #[warn(dead_code)] on by default
|
||||
| ^
|
||||
```
|
||||
|
||||
Only one warning left! Try to fix this one on your own!
|
||||
Only one warning is left! Try to fix this one on your own!
|
||||
|
||||
### Privacy Rules
|
||||
|
||||
Overall, these are the rules for item visibility:
|
||||
|
||||
1. If an item is public, it can be accessed through any of its parent modules.
|
||||
2. If an item is private, it may be accessed only by the current module and its
|
||||
child modules.
|
||||
2. If an item is private, it can be accessed only by the current module and its
|
||||
child modules.
|
||||
|
||||
### Privacy Examples
|
||||
|
||||
Let’s look at a few more examples to get some practice. Create a new library
|
||||
project and enter the code in Listing 7-5 into your new project’s *src/lib.rs*:
|
||||
Let’s look at a few more privacy examples to get some practice. Create a new
|
||||
library project and enter the code in Listing 7-5 into your new project’s
|
||||
*src/lib.rs*:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -741,24 +754,24 @@ fn try_me() {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-5: Examples of private and public functions,
|
||||
some of which are incorrect
|
||||
Listing 7-5: Examples of private and public functions, some of which are
|
||||
incorrect
|
||||
|
||||
Before you try to compile this code, make a guess about which lines in `try_me`
|
||||
function will have errors. Then try compiling to see if you were right, and
|
||||
read on for discussion of the errors!
|
||||
Before you try to compile this code, make a guess about which lines in the
|
||||
`try_me` function will have errors. Then, try compiling the code to see whether
|
||||
you were right, and read on for the discussion of the errors!
|
||||
|
||||
#### Looking at the Errors
|
||||
|
||||
The `try_me` function is in the root module of our project. The module named
|
||||
`outermost` is private, but the second privacy rule says the `try_me` function
|
||||
is allowed to access the `outermost` module since `outermost` is in the current
|
||||
(root) module, as is `try_me`.
|
||||
`outermost` is private, but the second privacy rule states that the `try_me`
|
||||
function is allowed to access the `outermost` module because `outermost` is in
|
||||
the current (root) module, as is `try_me`.
|
||||
|
||||
The call to `outermost::middle_function` will work. This is because
|
||||
`middle_function` is public, and `try_me` is accessing `middle_function`
|
||||
through its parent module, `outermost`. We determined in the previous paragraph
|
||||
that this module is accessible.
|
||||
The call to `outermost::middle_function` will work because `middle_function` is
|
||||
public, and `try_me` is accessing `middle_function` through its parent module
|
||||
`outermost`. We determined in the previous paragraph that this module is
|
||||
accessible.
|
||||
|
||||
The call to `outermost::middle_secret_function` will cause a compilation error.
|
||||
`middle_secret_function` is private, so the second rule applies. The root
|
||||
@@ -766,16 +779,16 @@ module is neither the current module of `middle_secret_function` (`outermost`
|
||||
is), nor is it a child module of the current module of `middle_secret_function`.
|
||||
|
||||
The module named `inside` is private and has no child modules, so it can only
|
||||
be accessed by its current module, `outermost`. That means the `try_me`
|
||||
function is not allowed to call `outermost::inside::inner_function` or
|
||||
`outermost::inside::secret_function` either.
|
||||
be accessed by its current module `outermost`. That means the `try_me` function
|
||||
is not allowed to call `outermost::inside::inner_function` or
|
||||
`outermost::inside::secret_function`.
|
||||
|
||||
#### Fixing the Errors
|
||||
|
||||
Here are some suggestions for changing the code in an attempt to fix the
|
||||
errors. Before you try each one, make a guess as to whether it will fix the
|
||||
errors, then compile to see if you’re right and use the privacy rules to
|
||||
understand why.
|
||||
errors, and then compile the code to see whether or not you’re right, using the
|
||||
privacy rules to understand why.
|
||||
|
||||
* What if the `inside` module was public?
|
||||
* What if `outermost` was public and `inside` was private?
|
||||
@@ -785,13 +798,13 @@ understand why.
|
||||
|
||||
Feel free to design more experiments and try them out!
|
||||
|
||||
Next, let’s talk about bringing items into a scope with the `use` keyword.
|
||||
Next, let’s talk about bringing items into scope with the `use` keyword.
|
||||
|
||||
## Importing Names
|
||||
|
||||
We’ve covered how to call functions defined within a module using the module
|
||||
name as part of the call, as in the call to the `nested_modules` function shown
|
||||
here in Listing 7-6.
|
||||
here in Listing 7-6:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -809,17 +822,16 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Listing 7-6: Calling a function by fully specifying its
|
||||
enclosing module’s namespaces
|
||||
Listing 7-6: Calling a function by fully specifying its enclosing module’s path
|
||||
|
||||
As you can see, referring to the fully qualified name can get quite lengthy.
|
||||
Luckily, Rust has a keyword to make these calls more concise.
|
||||
Fortunately, Rust has a keyword to make these calls more concise.
|
||||
|
||||
### Concise Imports with `use`
|
||||
|
||||
Rust’s `use` keyword works to shorten lengthy function calls by bringing the
|
||||
modules of the function you want to call into a scope. Here’s an example of
|
||||
bringing the `a::series::of` module into a binary crate’s root scope:
|
||||
Rust’s `use` keyword shortens lengthy function calls by bringing the modules of
|
||||
the function you want to call into scope. Here’s an example of bringing the
|
||||
`a::series::of` module into a binary crate’s root scope:
|
||||
|
||||
Filename: src/main.rs
|
||||
|
||||
@@ -843,12 +855,12 @@ The line `use a::series::of;` means that rather than using the full
|
||||
`a::series::of` path wherever we want to refer to the `of` module, we can use
|
||||
`of`.
|
||||
|
||||
The `use` keyword brings only what we have specified into scope; it does not
|
||||
bring children of modules into scope. That’s why we still have to say
|
||||
The `use` keyword brings only what we’ve specified into scope: it does not
|
||||
bring children of modules into scope. That’s why we still have to use
|
||||
`of::nested_modules` when we want to call the `nested_modules` function.
|
||||
|
||||
We could have chosen to bring the function itself into scope, by instead
|
||||
specifying the function in the `use` as follows:
|
||||
We could have chosen to bring the function into scope by instead specifying the
|
||||
function in the `use` as follows:
|
||||
|
||||
```
|
||||
pub mod a {
|
||||
@@ -866,11 +878,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
This allows us to exclude all of the modules and reference the function
|
||||
Doing so allows us to exclude all the modules and reference the function
|
||||
directly.
|
||||
|
||||
Since enums also form a sort of namespace like modules, we can import an enum’s
|
||||
variants with `use` as well. For any kind of `use` statement, if you’re
|
||||
Because enums also form a sort of namespace like modules, we can import an
|
||||
enum’s variants with `use` as well. For any kind of `use` statement, if you’re
|
||||
importing multiple items from one namespace, you can list them using curly
|
||||
braces and commas in the last position, like so:
|
||||
|
||||
@@ -886,10 +898,13 @@ use TrafficLight::{Red, Yellow};
|
||||
fn main() {
|
||||
let red = Red;
|
||||
let yellow = Yellow;
|
||||
let green = TrafficLight::Green; // because we didn’t `use` TrafficLight::Green
|
||||
let green = TrafficLight::Green;
|
||||
}
|
||||
```
|
||||
|
||||
We're still specifying the `TrafficLight` namespace for the `Green` variant
|
||||
because we didn't include `Green` in the `use` statement.
|
||||
|
||||
### Glob Imports with `*`
|
||||
|
||||
To import all the items in a namespace at once, we can use the `*` syntax. For
|
||||
@@ -911,15 +926,15 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
The `*` is called a *glob*, and it will import everything that’s visible inside
|
||||
of the namespace. Globs should be used sparingly: they are convenient, but you
|
||||
might also pull in more things than you expected and cause naming conflicts.
|
||||
The `*` is called a *glob*, and it will import all items visible inside the
|
||||
namespace. You should use globs sparingly: they are convenient, but this might
|
||||
also pull in more items than you expected and cause naming conflicts.
|
||||
|
||||
### Using `super` to Access a Parent Module
|
||||
|
||||
As you now know, when you create a library crate, Cargo makes a `tests` module
|
||||
for you. Let’s go into more detail about that now. In your `communicator`
|
||||
project, open *src/lib.rs*.
|
||||
As we saw at the beginning of this chapter, when you create a library crate,
|
||||
Cargo makes a `tests` module for you. Let’s go into more detail about that now.
|
||||
In your `communicator` project, open *src/lib.rs*:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -936,12 +951,14 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
We’ll explain more about testing in Chapter 11, but parts of this should make
|
||||
Chapter 11 explains more about testing, but parts of this example should make
|
||||
sense now: we have a module named `tests` that lives next to our other modules
|
||||
and contains one function named `it_works`. Even though there are special
|
||||
annotations, the `tests` module is just another module! So our module hierarchy
|
||||
looks like this:
|
||||
|
||||
Prod: Check xref
|
||||
|
||||
```
|
||||
communicator
|
||||
├── client
|
||||
@@ -951,8 +968,8 @@ communicator
|
||||
```
|
||||
|
||||
Tests are for exercising the code within our library, so let’s try to call our
|
||||
`client::connect` function from this `it_works` function, even though we’re not
|
||||
going to be checking any functionality right now:
|
||||
`client::connect` function from this `it_works` function, even though we won’t
|
||||
be checking any functionality right now:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -985,37 +1002,37 @@ always relative to the current module, which here is `tests`. The only
|
||||
exception is in a `use` statement, where paths are relative to the crate root
|
||||
by default. Our `tests` module needs the `client` module in its scope!
|
||||
|
||||
So how do we get back up one module in the module hierarchy to be able to call
|
||||
the `client::connect` function in the `tests` module? In the `tests` module, we
|
||||
can either use leading colons to let Rust know that we want to start from the
|
||||
root and list the whole path:
|
||||
So how do we get back up one module in the module hierarchy to call the
|
||||
`client::connect` function in the `tests` module? In the `tests` module, we can
|
||||
either use leading colons to let Rust know that we want to start from the root
|
||||
and list the whole path, like this:
|
||||
|
||||
```
|
||||
::client::connect();
|
||||
```
|
||||
|
||||
Or we can use `super` to move up one module in the hierarchy from our current
|
||||
module:
|
||||
Or, we can use `super` to move up one module in the hierarchy from our current
|
||||
module, like this:
|
||||
|
||||
```
|
||||
super::client::connect();
|
||||
```
|
||||
|
||||
These two options don’t look all that different in this example, but if you’re
|
||||
deeper in a module hierarchy, starting from the root every time would get long.
|
||||
In those cases, using `super` to get from the current module to sibling modules
|
||||
is a good shortcut. Plus, if you’ve specified the path from the root in many
|
||||
places in your code and then you rearrange your modules by moving a subtree to
|
||||
another place, you’d end up needing to update the path in a lot of places,
|
||||
which would be tedious.
|
||||
These two options don’t look that different in this example, but if you’re
|
||||
deeper in a module hierarchy, starting from the root every time would make your
|
||||
code lengthy. In those cases, using `super` to get from the current module to
|
||||
sibling modules is a good shortcut. Plus, if you’ve specified the path from the
|
||||
root in many places in your code and then you rearrange your modules by moving
|
||||
a subtree to another place, you’d end up needing to update the path in several
|
||||
places, which would be tedious.
|
||||
|
||||
It would also be annoying to have to type `super::` all the time in each test,
|
||||
but you’ve already seen the tool for that solution: `use`! The `super::`
|
||||
functionality changes the path you give to `use` so that it is relative to the
|
||||
parent module instead of to the root module.
|
||||
It would also be annoying to have to type `super::` in each test, but you’ve
|
||||
already seen the tool for that solution: `use`! The `super::` functionality
|
||||
changes the path you give to `use` so it is relative to the parent module
|
||||
instead of to the root module.
|
||||
|
||||
For these reasons, in the `tests` module especially, `use super::something` is
|
||||
usually the way to go. So now our test looks like this:
|
||||
usually the best solution. So now our test looks like this:
|
||||
|
||||
Filename: src/lib.rs
|
||||
|
||||
@@ -1031,8 +1048,8 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
If we run `cargo test` again, the test will pass and the first part of the test
|
||||
result output will be:
|
||||
When we run `cargo test` again, the test will pass and the first part of the
|
||||
test result output will be the following:
|
||||
|
||||
```
|
||||
$ cargo test
|
||||
@@ -1047,9 +1064,10 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
## Summary
|
||||
|
||||
Now you know techniques for organizing your code! Use these to group related
|
||||
functionality together, keep files from getting too long, and present a tidy
|
||||
public API to users of your library.
|
||||
Now you know some new techniques for organizing your code! Use these techniques
|
||||
to group related functionality together, keep files from becoming too long, and
|
||||
present a tidy public API to your library users.
|
||||
|
||||
Next, we’ll look at some collection data structures in the standard library
|
||||
that you can use in your nice, neat code!
|
||||
|
||||
Next, let’s look at some collection data structures in the standard library
|
||||
that you can make use of in your nice, neat code!
|
||||
|
||||
Reference in New Issue
Block a user