summaryrefslogtreecommitdiffstats
path: root/src/doc/book/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md
diff options
context:
space:
mode:
Diffstat (limited to 'src/doc/book/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md')
-rw-r--r--src/doc/book/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md298
1 files changed, 298 insertions, 0 deletions
diff --git a/src/doc/book/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md b/src/doc/book/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md
new file mode 100644
index 000000000..c8fb3247f
--- /dev/null
+++ b/src/doc/book/src/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.md
@@ -0,0 +1,298 @@
+## Paths for Referring to an Item in the Module Tree
+
+To show Rust where to find an item in a module tree, we use a path in the same
+way we use a path when navigating a filesystem. To call a function, we need to
+know its path.
+
+A path can take two forms:
+
+* An *absolute path* is the full path starting from a crate root; for code
+ from an external crate, the absolute path begins with the crate name, and for
+ code from the current crate, it starts with the literal `crate`.
+* A *relative path* starts from the current module and uses `self`, `super`, or
+ an identifier in the current module.
+
+Both absolute and relative paths are followed by one or more identifiers
+separated by double colons (`::`).
+
+Returning to Listing 7-1, say we want to call the `add_to_waitlist` function.
+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
+there’s another problem remaining that will prevent this example from compiling
+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`
+Keyword”][pub]<!-- ignore --> section, we’ll go into more detail about `pub`.
+
+<span class="filename">Filename: src/lib.rs</span>
+
+```rust,ignore,does_not_compile
+{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-03/src/lib.rs}}
+```
+
+<span class="caption">Listing 7-3: Calling the `add_to_waitlist` function using
+absolute and relative paths</span>
+
+The first time we call the `add_to_waitlist` function in `eat_at_restaurant`,
+we use an absolute path. The `add_to_waitlist` function is defined in the same
+crate as `eat_at_restaurant`, which means we can use the `crate` keyword to
+start an absolute path. We then include each of the successive modules until we
+make our way to `add_to_waitlist`. You can imagine a filesystem with the same
+structure: we’d specify the path `/front_of_house/hosting/add_to_waitlist` to
+run the `add_to_waitlist` program; using the `crate` name to start from the
+crate root is like using `/` to start from the filesystem root in your shell.
+
+The second time we call `add_to_waitlist` in `eat_at_restaurant`, we use a
+relative path. The path starts with `front_of_house`, the name of the module
+defined at the same level of the module tree as `eat_at_restaurant`. Here the
+filesystem equivalent would be using the path
+`front_of_house/hosting/add_to_waitlist`. Starting with a module name means
+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.
+
+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.
+
+```console
+{{#include ../listings/ch07-managing-growing-projects/listing-07-03/output.txt}}
+```
+
+<span class="caption">Listing 7-4: Compiler errors from building the code in
+Listing 7-3</span>
+
+The error messages say that module `hosting` is private. In other words, we
+have the correct paths for the `hosting` module and the `add_to_waitlist`
+function, but Rust 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.
+
+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.
+
+Rust chose to have the module system function this way so that hiding inner
+implementation details is the default. That way, you know which parts of the
+inner code you can change without breaking outer code. However, Rust does give
+you the option to expose inner parts of child modules’ code to outer ancestor
+modules by using the `pub` keyword to make an item public.
+
+### Exposing Paths with the `pub` Keyword
+
+Let’s return to the error in Listing 7-4 that told us the `hosting` module is
+private. We want the `eat_at_restaurant` function in the parent module to have
+access to the `add_to_waitlist` function in the child module, so we mark the
+`hosting` module with the `pub` keyword, as shown in Listing 7-5.
+
+<span class="filename">Filename: src/lib.rs</span>
+
+```rust,ignore,does_not_compile
+{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-05/src/lib.rs}}
+```
+
+<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.
+
+```console
+{{#include ../listings/ch07-managing-growing-projects/listing-07-05/output.txt}}
+```
+
+<span class="caption">Listing 7-6: Compiler errors from building the code in
+Listing 7-5</span>
+
+What happened? Adding the `pub` keyword in front of `mod hosting` makes the
+module public. With this change, if we can access `front_of_house`, we can
+access `hosting`. But the *contents* of `hosting` are still private; making the
+module public doesn’t make its contents public. The `pub` 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.
+
+The errors in Listing 7-6 say that the `add_to_waitlist` function is private.
+The privacy rules apply to structs, enums, functions, and methods as well as
+modules.
+
+Let’s also make the `add_to_waitlist` function public by adding the `pub`
+keyword before its definition, as in Listing 7-7.
+
+<span class="filename">Filename: src/lib.rs</span>
+
+```rust,noplayground,test_harness
+{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs}}
+```
+
+<span class="caption">Listing 7-7: Adding the `pub` keyword to `mod hosting`
+and `fn add_to_waitlist` lets us call the function from
+`eat_at_restaurant`</span>
+
+Now the code will compile! To see why adding the `pub` keyword lets us use
+these paths in `add_to_waitlist` with respect to the privacy rules, let’s look
+at the absolute and the relative paths.
+
+In the absolute path, we start with `crate`, the root of our crate’s module
+tree. The `front_of_house` module is defined in the crate root. While
+`front_of_house` isn’t public, because the `eat_at_restaurant` function is
+defined in the same module as `front_of_house` (that is, `eat_at_restaurant`
+and `front_of_house` are siblings), we can refer to `front_of_house` from
+`eat_at_restaurant`. Next is the `hosting` module marked with `pub`. We can
+access the parent module of `hosting`, so we can access `hosting`. Finally, the
+`add_to_waitlist` function is marked with `pub` and we can access its parent
+module, so this function call works!
+
+In the relative path, the logic is the same as the absolute path except for the
+first step: rather than starting from the crate root, the path starts from
+`front_of_house`. The `front_of_house` module is defined within the same module
+as `eat_at_restaurant`, so the relative path starting from the module in which
+`eat_at_restaurant` is defined works. Then, because `hosting` and
+`add_to_waitlist` are marked with `pub`, the rest of the path works, and this
+function call is valid!
+
+If you plan on sharing your library crate so other projects can use your code,
+your public API is your contract with users of your crate that determines how
+they can interact with your code. There are many considerations around managing
+changes to your public API to make it easier for people to depend on your
+crate. These considerations are out of the scope of this book; if you’re
+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 with 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.
+>
+> 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.
+> 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, you’re also a
+> client!
+>
+> In [Chapter 12][ch12]<!-- ignore -->, we’ll demonstrate this organizational
+> practice with a command-line program that will contain both a binary crate
+> and a library crate.
+
+### Starting Relative Paths with `super`
+
+We can construct relative paths that begin in the parent module, rather than
+the current module or the crate root, by using `super` at the start of the
+path. This is like starting a filesystem path with the `..` syntax. 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
+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`:
+
+<span class="filename">Filename: src/lib.rs</span>
+
+```rust,noplayground,test_harness
+{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs}}
+```
+
+<span class="caption">Listing 7-8: Calling a function using a relative path
+starting with `super`</span>
+
+The `fix_incorrect_order` function is in the `back_of_house` module, so we can
+use `super` to go to the parent module of `back_of_house`, which in this case
+is `crate`, the root. From there, we look for `deliver_order` and find it.
+Success! We think the `back_of_house` module and the `deliver_order` 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 `super` so we’ll have fewer places to update code in the future if this
+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`
+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
+with a public `toast` field but a private `seasonal_fruit` field. This models
+the case in a restaurant where the customer can pick the type of bread that
+comes with a meal, but the chef decides which fruit accompanies the meal based
+on 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.
+
+<span class="filename">Filename: src/lib.rs</span>
+
+```rust,noplayground
+{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-09/src/lib.rs}}
+```
+
+<span class="caption">Listing 7-9: A struct with some public fields and some
+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
+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
+struct needs to provide a public associated function that constructs an
+instance of `Breakfast` (we’ve named it `summer` here). If `Breakfast` didn’t
+have such a function, we couldn’t create an instance of `Breakfast` in
+`eat_at_restaurant` because we couldn’t set the value of the private
+`seasonal_fruit` field in `eat_at_restaurant`.
+
+In contrast, if we make an enum public, all of its variants are then public. We
+only need the `pub` before the `enum` keyword, as shown in Listing 7-10.
+
+<span class="filename">Filename: src/lib.rs</span>
+
+```rust,noplayground
+{{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-10/src/lib.rs}}
+```
+
+<span class="caption">Listing 7-10: Designating an enum as public makes all its
+variants public</span>
+
+Because we made the `Appetizer` enum public, we can use the `Soup` and `Salad`
+variants in `eat_at_restaurant`.
+
+Enums aren’t very useful unless their variants are public; it would be annoying
+to have to annotate all enum variants with `pub` in every case, so the default
+for enum variants is to be public. Structs are often useful without their
+fields being public, so struct fields follow the general rule of everything
+being private by default unless annotated with `pub`.
+
+There’s one more situation involving `pub` that we haven’t covered, and that is
+our last module system feature: the `use` keyword. We’ll cover `use` by itself
+first, and then we’ll show how to combine `pub` and `use`.
+
+[pub]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#exposing-paths-with-the-pub-keyword
+[api-guidelines]: https://rust-lang.github.io/api-guidelines/
+[ch12]: ch12-00-an-io-project.html