380 lines
22 KiB
HTML
380 lines
22 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Paths for Referring to an Item in the Module Tree</title>
|
||
</head>
|
||
<body>
|
||
<h2 id="paths-for-referring-to-an-item-in-the-module-tree"><a class="header" href="#paths-for-referring-to-an-item-in-the-module-tree">Paths for Referring to an Item in the Module Tree</a></h2>
|
||
<p>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. To call a function, we need to
|
||
know its path.</p>
|
||
<p>A path can take two forms:</p>
|
||
<ul>
|
||
<li>An <em>absolute path</em> 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 <code>crate</code>.</li>
|
||
<li>A <em>relative path</em> starts from the current module and uses <code>self</code>, <code>super</code>, or
|
||
an identifier in the current module.</li>
|
||
</ul>
|
||
<p>Both absolute and relative paths are followed by one or more identifiers
|
||
separated by double colons (<code>::</code>).</p>
|
||
<p>Returning to Listing 7-1, say we want to call the <code>add_to_waitlist</code> function.
|
||
This is the same as asking: What’s the path of the <code>add_to_waitlist</code> function?
|
||
Listing 7-3 contains Listing 7-1 with some of the modules and functions removed.</p>
|
||
<p>We’ll show two ways to call the <code>add_to_waitlist</code> function from a new function,
|
||
<code>eat_at_restaurant</code>, 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.</p>
|
||
<p>The <code>eat_at_restaurant</code> function is part of our library crate’s public API, so
|
||
we mark it with the <code>pub</code> keyword. In the <a href="ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#exposing-paths-with-the-pub-keyword">“Exposing Paths with the <code>pub</code>
|
||
Keyword”</a><!-- ignore --> section, we’ll go into more detail about <code>pub</code>.</p>
|
||
<figure class="listing" id="listing-7-3">
|
||
<span class="file-name">Filename: src/lib.rs</span>
|
||
<pre><code class="language-rust ignore does_not_compile">mod front_of_house {
|
||
mod hosting {
|
||
fn add_to_waitlist() {}
|
||
}
|
||
}
|
||
|
||
pub fn eat_at_restaurant() {
|
||
// Absolute path
|
||
crate::front_of_house::hosting::add_to_waitlist();
|
||
|
||
// Relative path
|
||
front_of_house::hosting::add_to_waitlist();
|
||
}</code></pre>
|
||
<figcaption><a href="#listing-7-3">Listing 7-3</a>: Calling the <code>add_to_waitlist</code> function using absolute and relative paths</figcaption>
|
||
</figure>
|
||
<p>The first time we call the <code>add_to_waitlist</code> function in <code>eat_at_restaurant</code>,
|
||
we use an absolute path. The <code>add_to_waitlist</code> function is defined in the same
|
||
crate as <code>eat_at_restaurant</code>, which means we can use the <code>crate</code> keyword to
|
||
start an absolute path. We then include each of the successive modules until we
|
||
make our way to <code>add_to_waitlist</code>. You can imagine a filesystem with the same
|
||
structure: We’d specify the path <code>/front_of_house/hosting/add_to_waitlist</code> to
|
||
run the <code>add_to_waitlist</code> program; using the <code>crate</code> name to start from the
|
||
crate root is like using <code>/</code> to start from the filesystem root in your shell.</p>
|
||
<p>The second time we call <code>add_to_waitlist</code> in <code>eat_at_restaurant</code>, we use a
|
||
relative path. The path starts with <code>front_of_house</code>, the name of the module
|
||
defined at the same level of the module tree as <code>eat_at_restaurant</code>. Here the
|
||
filesystem equivalent would be using the path
|
||
<code>front_of_house/hosting/add_to_waitlist</code>. Starting with a module name means
|
||
that the path is relative.</p>
|
||
<p>Choosing whether to use a relative or absolute path is a decision you’ll make
|
||
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 <code>front_of_house</code> module and the
|
||
<code>eat_at_restaurant</code> function into a module named <code>customer_experience</code>, we’d
|
||
need to update the absolute path to <code>add_to_waitlist</code>, but the relative path
|
||
would still be valid. However, if we moved the <code>eat_at_restaurant</code> function
|
||
separately into a module named <code>dining</code>, the absolute path to the
|
||
<code>add_to_waitlist</code> 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.</p>
|
||
<p>Let’s try to compile Listing 7-3 and find out why it won’t compile yet! The
|
||
errors we get are shown in Listing 7-4.</p>
|
||
<figure class="listing" id="listing-7-4">
|
||
<pre><code class="language-console">$ cargo build
|
||
Compiling restaurant v0.1.0 (file:///projects/restaurant)
|
||
error[E0603]: module `hosting` is private
|
||
--> src/lib.rs:9:28
|
||
|
|
||
9 | crate::front_of_house::hosting::add_to_waitlist();
|
||
| ^^^^^^^ --------------- function `add_to_waitlist` is not publicly re-exported
|
||
| |
|
||
| private module
|
||
|
|
||
note: the module `hosting` is defined here
|
||
--> src/lib.rs:2:5
|
||
|
|
||
2 | mod hosting {
|
||
| ^^^^^^^^^^^
|
||
|
||
error[E0603]: module `hosting` is private
|
||
--> src/lib.rs:12:21
|
||
|
|
||
12 | front_of_house::hosting::add_to_waitlist();
|
||
| ^^^^^^^ --------------- function `add_to_waitlist` is not publicly re-exported
|
||
| |
|
||
| private module
|
||
|
|
||
note: the module `hosting` is defined here
|
||
--> src/lib.rs:2:5
|
||
|
|
||
2 | mod hosting {
|
||
| ^^^^^^^^^^^
|
||
|
||
For more information about this error, try `rustc --explain E0603`.
|
||
error: could not compile `restaurant` (lib) due to 2 previous errors
|
||
</code></pre>
|
||
<figcaption><a href="#listing-7-4">Listing 7-4</a>: Compiler errors from building the code in Listing 7-3</figcaption>
|
||
</figure>
|
||
<p>The error messages say that module <code>hosting</code> is private. In other words, we
|
||
have the correct paths for the <code>hosting</code> module and the <code>add_to_waitlist</code>
|
||
function, but Rust won’t let us use them because it doesn’t have access to the
|
||
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.</p>
|
||
<p>Items in a parent module can’t 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 they’re 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.</p>
|
||
<p>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 the outer code. However, Rust does
|
||
give you the option to expose inner parts of child modules’ code to outer
|
||
ancestor modules by using the <code>pub</code> keyword to make an item public.</p>
|
||
<h3 id="exposing-paths-with-the-pub-keyword"><a class="header" href="#exposing-paths-with-the-pub-keyword">Exposing Paths with the <code>pub</code> Keyword</a></h3>
|
||
<p>Let’s return to the error in Listing 7-4 that told us the <code>hosting</code> module is
|
||
private. We want the <code>eat_at_restaurant</code> function in the parent module to have
|
||
access to the <code>add_to_waitlist</code> function in the child module, so we mark the
|
||
<code>hosting</code> module with the <code>pub</code> keyword, as shown in Listing 7-5.</p>
|
||
<figure class="listing" id="listing-7-5">
|
||
<span class="file-name">Filename: src/lib.rs</span>
|
||
<pre><code class="language-rust ignore does_not_compile">mod front_of_house {
|
||
pub mod hosting {
|
||
fn add_to_waitlist() {}
|
||
}
|
||
}
|
||
|
||
// -- snip --
|
||
<span class="boring">pub fn eat_at_restaurant() {
|
||
</span><span class="boring"> // Absolute path
|
||
</span><span class="boring"> crate::front_of_house::hosting::add_to_waitlist();
|
||
</span><span class="boring">
|
||
</span><span class="boring"> // Relative path
|
||
</span><span class="boring"> front_of_house::hosting::add_to_waitlist();
|
||
</span><span class="boring">}</span></code></pre>
|
||
<figcaption><a href="#listing-7-5">Listing 7-5</a>: Declaring the <code>hosting</code> module as <code>pub</code> to use it from <code>eat_at_restaurant</code></figcaption>
|
||
</figure>
|
||
<p>Unfortunately, the code in Listing 7-5 still results in compiler errors, as
|
||
shown in Listing 7-6.</p>
|
||
<figure class="listing" id="listing-7-6">
|
||
<pre><code class="language-console">$ cargo build
|
||
Compiling restaurant v0.1.0 (file:///projects/restaurant)
|
||
error[E0603]: function `add_to_waitlist` is private
|
||
--> src/lib.rs:10:37
|
||
|
|
||
10 | crate::front_of_house::hosting::add_to_waitlist();
|
||
| ^^^^^^^^^^^^^^^ private function
|
||
|
|
||
note: the function `add_to_waitlist` is defined here
|
||
--> src/lib.rs:3:9
|
||
|
|
||
3 | fn add_to_waitlist() {}
|
||
| ^^^^^^^^^^^^^^^^^^^^
|
||
|
||
error[E0603]: function `add_to_waitlist` is private
|
||
--> src/lib.rs:13:30
|
||
|
|
||
13 | front_of_house::hosting::add_to_waitlist();
|
||
| ^^^^^^^^^^^^^^^ private function
|
||
|
|
||
note: the function `add_to_waitlist` is defined here
|
||
--> src/lib.rs:3:9
|
||
|
|
||
3 | fn add_to_waitlist() {}
|
||
| ^^^^^^^^^^^^^^^^^^^^
|
||
|
||
For more information about this error, try `rustc --explain E0603`.
|
||
error: could not compile `restaurant` (lib) due to 2 previous errors
|
||
</code></pre>
|
||
<figcaption><a href="#listing-7-6">Listing 7-6</a>: Compiler errors from building the code in Listing 7-5</figcaption>
|
||
</figure>
|
||
<p>What happened? Adding the <code>pub</code> keyword in front of <code>mod hosting</code> makes the
|
||
module public. With this change, if we can access <code>front_of_house</code>, we can
|
||
access <code>hosting</code>. But the <em>contents</em> of <code>hosting</code> are still private; making the
|
||
module public doesn’t make its contents public. The <code>pub</code> keyword on a module
|
||
only lets code in its ancestor modules refer to it, not access its inner code.
|
||
Because modules are containers, there’s 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.</p>
|
||
<p>The errors in Listing 7-6 say that the <code>add_to_waitlist</code> function is private.
|
||
The privacy rules apply to structs, enums, functions, and methods as well as
|
||
modules.</p>
|
||
<p>Let’s also make the <code>add_to_waitlist</code> function public by adding the <code>pub</code>
|
||
keyword before its definition, as in Listing 7-7.</p>
|
||
<figure class="listing" id="listing-7-7">
|
||
<span class="file-name">Filename: src/lib.rs</span>
|
||
<pre><code class="language-rust noplayground test_harness">mod front_of_house {
|
||
pub mod hosting {
|
||
pub fn add_to_waitlist() {}
|
||
}
|
||
}
|
||
|
||
// -- snip --
|
||
<span class="boring">pub fn eat_at_restaurant() {
|
||
</span><span class="boring"> // Absolute path
|
||
</span><span class="boring"> crate::front_of_house::hosting::add_to_waitlist();
|
||
</span><span class="boring">
|
||
</span><span class="boring"> // Relative path
|
||
</span><span class="boring"> front_of_house::hosting::add_to_waitlist();
|
||
</span><span class="boring">}</span></code></pre>
|
||
<figcaption><a href="#listing-7-7">Listing 7-7</a>: Adding the <code>pub</code> keyword to <code>mod hosting</code> and <code>fn add_to_waitlist</code> lets us call the function from <code>eat_at_restaurant</code>.</figcaption>
|
||
</figure>
|
||
<p>Now the code will compile! To see why adding the <code>pub</code> keyword lets us use
|
||
these paths in <code>eat_at_restaurant</code> with respect to the privacy rules, let’s
|
||
look at the absolute and the relative paths.</p>
|
||
<p>In the absolute path, we start with <code>crate</code>, the root of our crate’s module
|
||
tree. The <code>front_of_house</code> module is defined in the crate root. While
|
||
<code>front_of_house</code> isn’t public, because the <code>eat_at_restaurant</code> function is
|
||
defined in the same module as <code>front_of_house</code> (that is, <code>eat_at_restaurant</code>
|
||
and <code>front_of_house</code> are siblings), we can refer to <code>front_of_house</code> from
|
||
<code>eat_at_restaurant</code>. Next is the <code>hosting</code> module marked with <code>pub</code>. We can
|
||
access the parent module of <code>hosting</code>, so we can access <code>hosting</code>. Finally, the
|
||
<code>add_to_waitlist</code> function is marked with <code>pub</code>, and we can access its parent
|
||
module, so this function call works!</p>
|
||
<p>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
|
||
<code>front_of_house</code>. The <code>front_of_house</code> module is defined within the same module
|
||
as <code>eat_at_restaurant</code>, so the relative path starting from the module in which
|
||
<code>eat_at_restaurant</code> is defined works. Then, because <code>hosting</code> and
|
||
<code>add_to_waitlist</code> are marked with <code>pub</code>, the rest of the path works, and this
|
||
function call is valid!</p>
|
||
<p>If you plan to share your library crate so that other projects can use your
|
||
code, 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 beyond the scope of this book; if you’re
|
||
interested in this topic, see <a href="https://rust-lang.github.io/api-guidelines/">the Rust API Guidelines</a>.</p>
|
||
<section class="note" aria-role="note">
|
||
<h4 id="best-practices-for-packages-with-a-binary-and-a-library"><a class="header" href="#best-practices-for-packages-with-a-binary-and-a-library">Best Practices for Packages with a Binary and a Library</a></h4>
|
||
<p>We mentioned that a package can contain both a <em>src/main.rs</em> binary crate
|
||
root as well as a <em>src/lib.rs</em> 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 defined in the library
|
||
crate. This lets other projects benefit from the most functionality that the
|
||
package provides because the library crate’s code can be shared.</p>
|
||
<p>The module tree should be defined in <em>src/lib.rs</em>. Then, any public items can
|
||
be used in the binary crate by starting paths with the name of the package.
|
||
The binary crate becomes a user of the library crate just like a completely
|
||
external crate would use the library crate: It can only use the public API.
|
||
This helps you design a good API; not only are you the author, but you’re
|
||
also a client!</p>
|
||
<p>In <a href="../ch12/ch12-00-an-io-project.html">Chapter 12</a><!-- ignore -->, we’ll demonstrate this organizational
|
||
practice with a command line program that will contain both a binary crate
|
||
and a library crate.</p>
|
||
</section>
|
||
<h3 id="starting-relative-paths-with-super"><a class="header" href="#starting-relative-paths-with-super">Starting Relative Paths with <code>super</code></a></h3>
|
||
<p>We can construct relative paths that begin in the parent module, rather than
|
||
the current module or the crate root, by using <code>super</code> at the start of the
|
||
path. This is like starting a filesystem path with the <code>..</code> syntax that means
|
||
to go to the parent directory. Using <code>super</code> 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.</p>
|
||
<p>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 <code>fix_incorrect_order</code> defined in the <code>back_of_house</code> module calls the
|
||
function <code>deliver_order</code> defined in the parent module by specifying the path to
|
||
<code>deliver_order</code>, starting with <code>super</code>.</p>
|
||
<figure class="listing" id="listing-7-8">
|
||
<span class="file-name">Filename: src/lib.rs</span>
|
||
<pre><code class="language-rust noplayground test_harness">fn deliver_order() {}
|
||
|
||
mod back_of_house {
|
||
fn fix_incorrect_order() {
|
||
cook_order();
|
||
super::deliver_order();
|
||
}
|
||
|
||
fn cook_order() {}
|
||
}</code></pre>
|
||
<figcaption><a href="#listing-7-8">Listing 7-8</a>: Calling a function using a relative path starting with <code>super</code></figcaption>
|
||
</figure>
|
||
<p>The <code>fix_incorrect_order</code> function is in the <code>back_of_house</code> module, so we can
|
||
use <code>super</code> to go to the parent module of <code>back_of_house</code>, which in this case
|
||
is <code>crate</code>, the root. From there, we look for <code>deliver_order</code> and find it.
|
||
Success! We think the <code>back_of_house</code> module and the <code>deliver_order</code> function
|
||
are likely to stay in the same relationship to each other and get moved
|
||
together should we decide to reorganize the crate’s module tree. Therefore, we
|
||
used <code>super</code> so that we’ll have fewer places to update code in the future if
|
||
this code gets moved to a different module.</p>
|
||
<h3 id="making-structs-and-enums-public"><a class="header" href="#making-structs-and-enums-public">Making Structs and Enums Public</a></h3>
|
||
<p>We can also use <code>pub</code> to designate structs and enums as public, but there are a
|
||
few extra details to the usage of <code>pub</code> with structs and enums. If we use <code>pub</code>
|
||
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 <code>back_of_house::Breakfast</code> struct
|
||
with a public <code>toast</code> field but a private <code>seasonal_fruit</code> 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 what’s in season and in stock. The available fruit changes quickly, so
|
||
customers can’t choose the fruit or even see which fruit they’ll get.</p>
|
||
<figure class="listing" id="listing-7-9">
|
||
<span class="file-name">Filename: src/lib.rs</span>
|
||
<pre><code class="language-rust noplayground">mod back_of_house {
|
||
pub struct Breakfast {
|
||
pub toast: String,
|
||
seasonal_fruit: String,
|
||
}
|
||
|
||
impl Breakfast {
|
||
pub fn summer(toast: &str) -> Breakfast {
|
||
Breakfast {
|
||
toast: String::from(toast),
|
||
seasonal_fruit: String::from("peaches"),
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
pub fn eat_at_restaurant() {
|
||
// Order a breakfast in the summer with Rye toast.
|
||
let mut meal = back_of_house::Breakfast::summer("Rye");
|
||
// Change our mind about what bread we'd like.
|
||
meal.toast = String::from("Wheat");
|
||
println!("I'd like {} toast please", meal.toast);
|
||
|
||
// The next line won't compile if we uncomment it; we're not allowed
|
||
// to see or modify the seasonal fruit that comes with the meal.
|
||
// meal.seasonal_fruit = String::from("blueberries");
|
||
}</code></pre>
|
||
<figcaption><a href="#listing-7-9">Listing 7-9</a>: A struct with some public fields and some private fields</figcaption>
|
||
</figure>
|
||
<p>Because the <code>toast</code> field in the <code>back_of_house::Breakfast</code> struct is public,
|
||
in <code>eat_at_restaurant</code> we can write and read to the <code>toast</code> field using dot
|
||
notation. Notice that we can’t use the <code>seasonal_fruit</code> field in
|
||
<code>eat_at_restaurant</code>, because <code>seasonal_fruit</code> is private. Try uncommenting the
|
||
line modifying the <code>seasonal_fruit</code> field value to see what error you get!</p>
|
||
<p>Also, note that because <code>back_of_house::Breakfast</code> has a private field, the
|
||
struct needs to provide a public associated function that constructs an
|
||
instance of <code>Breakfast</code> (we’ve named it <code>summer</code> here). If <code>Breakfast</code> didn’t
|
||
have such a function, we couldn’t create an instance of <code>Breakfast</code> in
|
||
<code>eat_at_restaurant</code>, because we couldn’t set the value of the private
|
||
<code>seasonal_fruit</code> field in <code>eat_at_restaurant</code>.</p>
|
||
<p>In contrast, if we make an enum public, all of its variants are then public. We
|
||
only need the <code>pub</code> before the <code>enum</code> keyword, as shown in Listing 7-10.</p>
|
||
<figure class="listing" id="listing-7-10">
|
||
<span class="file-name">Filename: src/lib.rs</span>
|
||
<pre><code class="language-rust noplayground">mod back_of_house {
|
||
pub enum Appetizer {
|
||
Soup,
|
||
Salad,
|
||
}
|
||
}
|
||
|
||
pub fn eat_at_restaurant() {
|
||
let order1 = back_of_house::Appetizer::Soup;
|
||
let order2 = back_of_house::Appetizer::Salad;
|
||
}</code></pre>
|
||
<figcaption><a href="#listing-7-10">Listing 7-10</a>: Designating an enum as public makes all its variants public.</figcaption>
|
||
</figure>
|
||
<p>Because we made the <code>Appetizer</code> enum public, we can use the <code>Soup</code> and <code>Salad</code>
|
||
variants in <code>eat_at_restaurant</code>.</p>
|
||
<p>Enums aren’t very useful unless their variants are public; it would be annoying
|
||
to have to annotate all enum variants with <code>pub</code> 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 <code>pub</code>.</p>
|
||
<p>There’s one more situation involving <code>pub</code> that we haven’t covered, and that is
|
||
our last module system feature: the <code>use</code> keyword. We’ll cover <code>use</code> by itself
|
||
first, and then we’ll show how to combine <code>pub</code> and <code>use</code>.</p>
|
||
</body>
|
||
</html>
|