]>
Commit | Line | Data |
---|---|---|
532ac7d7 XL |
1 | ## Paths for Referring to an Item in the Module Tree |
2 | ||
dc9dc135 XL |
3 | To show Rust where to find an item in a module tree, we use a path in the same |
4 | way we use a path when navigating a filesystem. If we want to call a function, | |
5 | we need to know its path. | |
532ac7d7 | 6 | |
dc9dc135 | 7 | A path can take two forms: |
532ac7d7 XL |
8 | |
9 | * An *absolute path* starts from a crate root by using a crate name or a | |
10 | literal `crate`. | |
11 | * A *relative path* starts from the current module and uses `self`, `super`, or | |
12 | an identifier in the current module. | |
13 | ||
14 | Both absolute and relative paths are followed by one or more identifiers | |
15 | separated by double colons (`::`). | |
16 | ||
17 | Let’s return to the example in Listing 7-1. How do we call the | |
18 | `add_to_waitlist` function? This is the same as asking, what’s the path of the | |
19 | `add_to_waitlist` function? In Listing 7-3, we simplified our code a bit by | |
20 | removing some of the modules and functions. We’ll show two ways to call the | |
21 | `add_to_waitlist` function from a new function `eat_at_restaurant` defined in | |
dc9dc135 XL |
22 | the crate root. The `eat_at_restaurant` function is part of our library crate’s |
23 | public API, so we mark it with the `pub` keyword. In the [”Exposing Paths with | |
24 | the `pub` Keyword”][pub]<!-- ignore --> section, we’ll go into more detail | |
416331ca XL |
25 | about `pub`. Note that this example won’t compile just yet; we’ll explain why |
26 | in a bit. | |
532ac7d7 XL |
27 | |
28 | <span class="filename">Filename: src/lib.rs</span> | |
29 | ||
30 | ```rust,ignore,does_not_compile | |
74b04a01 | 31 | {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-03/src/lib.rs}} |
532ac7d7 XL |
32 | ``` |
33 | ||
34 | <span class="caption">Listing 7-3: Calling the `add_to_waitlist` function using | |
35 | absolute and relative paths</span> | |
36 | ||
37 | The first time we call the `add_to_waitlist` function in `eat_at_restaurant`, | |
38 | we use an absolute path. The `add_to_waitlist` function is defined in the same | |
39 | crate as `eat_at_restaurant`, which means we can use the `crate` keyword to | |
40 | start an absolute path. | |
41 | ||
42 | After `crate`, we include each of the successive modules until we make our way | |
43 | to `add_to_waitlist`. You can imagine a filesystem with the same structure, and | |
44 | we’d specify the path `/front_of_house/hosting/add_to_waitlist` to run the | |
45 | `add_to_waitlist` program; using the `crate` name to start from the crate root | |
46 | is like using `/` to start from the filesystem root in your shell. | |
47 | ||
48 | The second time we call `add_to_waitlist` in `eat_at_restaurant`, we use a | |
49 | relative path. The path starts with `front_of_house`, the name of the module | |
50 | defined at the same level of the module tree as `eat_at_restaurant`. Here the | |
51 | filesystem equivalent would be using the path | |
52 | `front_of_house/hosting/add_to_waitlist`. Starting with a name means that the | |
53 | path is relative. | |
54 | ||
55 | Choosing whether to use a relative or absolute path is a decision you’ll make | |
56 | based on your project. The decision should depend on whether you’re more likely | |
57 | to move item definition code separately from or together with the code that | |
58 | uses the item. For example, if we move the `front_of_house` module and the | |
59 | `eat_at_restaurant` function into a module named `customer_experience`, we’d | |
60 | need to update the absolute path to `add_to_waitlist`, but the relative path | |
61 | would still be valid. However, if we moved the `eat_at_restaurant` function | |
62 | separately into a module named `dining`, the absolute path to the | |
63 | `add_to_waitlist` call would stay the same, but the relative path would need to | |
48663c56 XL |
64 | be updated. Our preference is to specify absolute paths because it’s more |
65 | likely to move code definitions and item calls independently of each other. | |
532ac7d7 XL |
66 | |
67 | Let’s try to compile Listing 7-3 and find out why it won’t compile yet! The | |
68 | error we get is shown in Listing 7-4. | |
69 | ||
f035d41b | 70 | ```console |
74b04a01 | 71 | {{#include ../listings/ch07-managing-growing-projects/listing-07-03/output.txt}} |
532ac7d7 XL |
72 | ``` |
73 | ||
74 | <span class="caption">Listing 7-4: Compiler errors from building the code in | |
75 | Listing 7-3</span> | |
76 | ||
77 | The error messages say that module `hosting` is private. In other words, we | |
78 | have the correct paths for the `hosting` module and the `add_to_waitlist` | |
79 | function, but Rust won’t let us use them because it doesn’t have access to the | |
80 | private sections. | |
81 | ||
dc9dc135 | 82 | Modules aren’t useful only for organizing your code. They also define Rust’s |
532ac7d7 XL |
83 | *privacy boundary*: the line that encapsulates the implementation details |
84 | external code isn’t allowed to know about, call, or rely on. So, if you want to | |
85 | make an item like a function or struct private, you put it in a module. | |
86 | ||
87 | The way privacy works in Rust is that all items (functions, methods, structs, | |
88 | enums, modules, and constants) are private by default. Items in a parent module | |
89 | can’t use the private items inside child modules, but items in child modules | |
90 | can use the items in their ancestor modules. The reason is that child modules | |
91 | wrap and hide their implementation details, but the child modules can see the | |
92 | context in which they’re defined. To continue with the restaurant metaphor, | |
dc9dc135 XL |
93 | think of the privacy rules as being like the back office of a restaurant: what |
94 | goes on in there is private to restaurant customers, but office managers can | |
95 | see and do everything in the restaurant in which they operate. | |
532ac7d7 XL |
96 | |
97 | Rust chose to have the module system function this way so that hiding inner | |
98 | implementation details is the default. That way, you know which parts of the | |
99 | inner code you can change without breaking outer code. But you can expose inner | |
ba9703b0 | 100 | parts of child modules' code to outer ancestor modules by using the `pub` |
dc9dc135 | 101 | keyword to make an item public. |
532ac7d7 XL |
102 | |
103 | ### Exposing Paths with the `pub` Keyword | |
104 | ||
105 | Let’s return to the error in Listing 7-4 that told us the `hosting` module is | |
106 | private. We want the `eat_at_restaurant` function in the parent module to have | |
107 | access to the `add_to_waitlist` function in the child module, so we mark the | |
108 | `hosting` module with the `pub` keyword, as shown in Listing 7-5. | |
109 | ||
110 | <span class="filename">Filename: src/lib.rs</span> | |
111 | ||
112 | ```rust,ignore,does_not_compile | |
74b04a01 | 113 | {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-05/src/lib.rs}} |
532ac7d7 XL |
114 | ``` |
115 | ||
116 | <span class="caption">Listing 7-5: Declaring the `hosting` module as `pub` to | |
117 | use it from `eat_at_restaurant`</span> | |
118 | ||
119 | Unfortunately, the code in Listing 7-5 still results in an error, as shown in | |
120 | Listing 7-6. | |
121 | ||
f035d41b | 122 | ```console |
74b04a01 | 123 | {{#include ../listings/ch07-managing-growing-projects/listing-07-05/output.txt}} |
532ac7d7 XL |
124 | ``` |
125 | ||
126 | <span class="caption">Listing 7-6: Compiler errors from building the code in | |
127 | Listing 7-5</span> | |
128 | ||
129 | What happened? Adding the `pub` keyword in front of `mod hosting` makes the | |
130 | module public. With this change, if we can access `front_of_house`, we can | |
131 | access `hosting`. But the *contents* of `hosting` are still private; making the | |
132 | module public doesn’t make its contents public. The `pub` keyword on a module | |
133 | only lets code in its ancestor modules refer to it. | |
134 | ||
135 | The errors in Listing 7-6 say that the `add_to_waitlist` function is private. | |
136 | The privacy rules apply to structs, enums, functions, and methods as well as | |
137 | modules. | |
138 | ||
139 | Let’s also make the `add_to_waitlist` function public by adding the `pub` | |
140 | keyword before its definition, as in Listing 7-7. | |
141 | ||
142 | <span class="filename">Filename: src/lib.rs</span> | |
143 | ||
144 | ```rust | |
74b04a01 | 145 | {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-07/src/lib.rs:here}} |
532ac7d7 XL |
146 | ``` |
147 | ||
148 | <span class="caption">Listing 7-7: Adding the `pub` keyword to `mod hosting` | |
149 | and `fn add_to_waitlist` lets us call the function from | |
150 | `eat_at_restaurant`</span> | |
151 | ||
dc9dc135 XL |
152 | Now the code will compile! Let’s look at the absolute and the relative path and |
153 | double-check why adding the `pub` keyword lets us use these paths in | |
532ac7d7 XL |
154 | `add_to_waitlist` with respect to the privacy rules. |
155 | ||
156 | In the absolute path, we start with `crate`, the root of our crate’s module | |
157 | tree. Then the `front_of_house` module is defined in the crate root. The | |
158 | `front_of_house` module isn’t public, but because the `eat_at_restaurant` | |
159 | function is defined in the same module as `front_of_house` (that is, | |
160 | `eat_at_restaurant` and `front_of_house` are siblings), we can refer to | |
161 | `front_of_house` from `eat_at_restaurant`. Next is the `hosting` module marked | |
162 | with `pub`. We can access the parent module of `hosting`, so we can access | |
163 | `hosting`. Finally, the `add_to_waitlist` function is marked with `pub` and we | |
164 | can access its parent module, so this function call works! | |
165 | ||
166 | In the relative path, the logic is the same as the absolute path except for the | |
167 | first step: rather than starting from the crate root, the path starts from | |
168 | `front_of_house`. The `front_of_house` module is defined within the same module | |
169 | as `eat_at_restaurant`, so the relative path starting from the module in which | |
170 | `eat_at_restaurant` is defined works. Then, because `hosting` and | |
dc9dc135 | 171 | `add_to_waitlist` are marked with `pub`, the rest of the path works, and this |
532ac7d7 XL |
172 | function call is valid! |
173 | ||
174 | ### Starting Relative Paths with `super` | |
175 | ||
176 | We can also construct relative paths that begin in the parent module by using | |
177 | `super` at the start of the path. This is like starting a filesystem path with | |
178 | the `..` syntax. Why would we want to do this? | |
179 | ||
180 | Consider the code in Listing 7-8 that models the situation in which a chef | |
181 | fixes an incorrect order and personally brings it out to the customer. The | |
182 | function `fix_incorrect_order` calls the function `serve_order` by specifying | |
183 | the path to `serve_order` starting with `super`: | |
184 | ||
185 | <span class="filename">Filename: src/lib.rs</span> | |
186 | ||
187 | ```rust | |
74b04a01 | 188 | {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-08/src/lib.rs:here}} |
532ac7d7 XL |
189 | ``` |
190 | ||
191 | <span class="caption">Listing 7-8: Calling a function using a relative path | |
192 | starting with `super`</span> | |
193 | ||
194 | The `fix_incorrect_order` function is in the `back_of_house` module, so we can | |
195 | use `super` to go to the parent module of `back_of_house`, which in this case | |
196 | is `crate`, the root. From there, we look for `serve_order` and find it. | |
197 | Success! We think the `back_of_house` module and the `serve_order` function are | |
198 | likely to stay in the same relationship to each other and get moved together | |
199 | should we decide to reorganize the crate’s module tree. Therefore, we used | |
200 | `super` so we’ll have fewer places to update code in the future if this code | |
201 | gets moved to a different module. | |
202 | ||
203 | ### Making Structs and Enums Public | |
204 | ||
205 | We can also use `pub` to designate structs and enums as public, but there are a | |
206 | few extra details. If we use `pub` before a struct definition, we make the | |
207 | struct public, but the struct’s fields will still be private. We can make each | |
208 | field public or not on a case-by-case basis. In Listing 7-9, we’ve defined a | |
209 | public `back_of_house::Breakfast` struct with a public `toast` field but a | |
210 | private `seasonal_fruit` field. This models the case in a restaurant where the | |
211 | customer can pick the type of bread that comes with a meal, but the chef | |
212 | decides which fruit accompanies the meal based on what’s in season and in | |
213 | stock. The available fruit changes quickly, so customers can’t choose the fruit | |
214 | or even see which fruit they’ll get. | |
215 | ||
216 | <span class="filename">Filename: src/lib.rs</span> | |
217 | ||
218 | ```rust | |
74b04a01 | 219 | {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-09/src/lib.rs}} |
532ac7d7 XL |
220 | ``` |
221 | ||
222 | <span class="caption">Listing 7-9: A struct with some public fields and some | |
223 | private fields</span> | |
224 | ||
225 | Because the `toast` field in the `back_of_house::Breakfast` struct is public, | |
226 | in `eat_at_restaurant` we can write and read to the `toast` field using dot | |
227 | notation. Notice that we can’t use the `seasonal_fruit` field in | |
228 | `eat_at_restaurant` because `seasonal_fruit` is private. Try uncommenting the | |
229 | line modifying the `seasonal_fruit` field value to see what error you get! | |
230 | ||
231 | Also, note that because `back_of_house::Breakfast` has a private field, the | |
232 | struct needs to provide a public associated function that constructs an | |
233 | instance of `Breakfast` (we’ve named it `summer` here). If `Breakfast` didn’t | |
234 | have such a function, we couldn’t create an instance of `Breakfast` in | |
dc9dc135 | 235 | `eat_at_restaurant` because we couldn’t set the value of the private |
532ac7d7 XL |
236 | `seasonal_fruit` field in `eat_at_restaurant`. |
237 | ||
238 | In contrast, if we make an enum public, all of its variants are then public. We | |
239 | only need the `pub` before the `enum` keyword, as shown in Listing 7-10. | |
240 | ||
241 | <span class="filename">Filename: src/lib.rs</span> | |
242 | ||
243 | ```rust | |
74b04a01 | 244 | {{#rustdoc_include ../listings/ch07-managing-growing-projects/listing-07-10/src/lib.rs}} |
532ac7d7 XL |
245 | ``` |
246 | ||
247 | <span class="caption">Listing 7-10: Designating an enum as public makes all its | |
248 | variants public</span> | |
249 | ||
250 | Because we made the `Appetizer` enum public, we can use the `Soup` and `Salad` | |
251 | variants in `eat_at_restaurant`. Enums aren’t very useful unless their variants | |
252 | are public; it would be annoying to have to annotate all enum variants with | |
253 | `pub` in every case, so the default for enum variants is to be public. Structs | |
254 | are often useful without their fields being public, so struct fields follow the | |
255 | general rule of everything being private by default unless annotated with `pub`. | |
256 | ||
257 | There’s one more situation involving `pub` that we haven’t covered, and that is | |
258 | our last module system feature: the `use` keyword. We’ll cover `use` by itself | |
259 | first, and then we’ll show how to combine `pub` and `use`. | |
48663c56 XL |
260 | |
261 | [pub]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html#exposing-paths-with-the-pub-keyword |