]>
Commit | Line | Data |
---|---|---|
cc61c64b XL |
1 | ## Controlling Visibility with `pub` |
2 | ||
3 | We resolved the error messages shown in Listing 7-4 by moving the `network` and | |
4 | `network::server` code into the *src/network/mod.rs* and | |
5 | *src/network/server.rs* files, respectively. At that point, `cargo build` was | |
7cac9316 | 6 | able to build our project, but we still get warning messages about the |
cc61c64b XL |
7 | `client::connect`, `network::connect`, and `network::server::connect` functions |
8 | not being used: | |
9 | ||
10 | ```text | |
abe05a73 XL |
11 | warning: function is never used: `connect` |
12 | --> src/client.rs:1:1 | |
cc61c64b | 13 | | |
abe05a73 XL |
14 | 1 | / fn connect() { |
15 | 2 | | } | |
16 | | |_^ | |
17 | | | |
18 | = note: #[warn(dead_code)] on by default | |
cc61c64b | 19 | |
abe05a73 | 20 | warning: function is never used: `connect` |
cc61c64b XL |
21 | --> src/network/mod.rs:1:1 |
22 | | | |
abe05a73 XL |
23 | 1 | / fn connect() { |
24 | 2 | | } | |
25 | | |_^ | |
cc61c64b | 26 | |
abe05a73 | 27 | warning: function is never used: `connect` |
cc61c64b XL |
28 | --> src/network/server.rs:1:1 |
29 | | | |
abe05a73 XL |
30 | 1 | / fn connect() { |
31 | 2 | | } | |
32 | | |_^ | |
cc61c64b XL |
33 | ``` |
34 | ||
35 | So why are we receiving these warnings? After all, we’re building a library | |
7cac9316 XL |
36 | with functions that are intended to be used by our *users*, not necessarily by |
37 | us within our own project, so it shouldn’t matter that these `connect` | |
cc61c64b | 38 | functions go unused. The point of creating them is that they will be used by |
7cac9316 | 39 | another project, not our own. |
cc61c64b XL |
40 | |
41 | To understand why this program invokes these warnings, let’s try using the | |
7cac9316 XL |
42 | `connect` library from another project, calling it externally. To do that, |
43 | we’ll create a binary crate in the same directory as our library crate by | |
44 | making a *src/main.rs* file containing this code: | |
cc61c64b XL |
45 | |
46 | <span class="filename">Filename: src/main.rs</span> | |
47 | ||
48 | ```rust,ignore | |
49 | extern crate communicator; | |
50 | ||
51 | fn main() { | |
52 | communicator::client::connect(); | |
53 | } | |
54 | ``` | |
55 | ||
56 | We use the `extern crate` command to bring the `communicator` library crate | |
7cac9316 XL |
57 | into scope. Our package now contains *two* crates. Cargo treats *src/main.rs* |
58 | as the root file of a binary crate, which is separate from the existing library | |
59 | crate whose root file is *src/lib.rs*. This pattern is quite common for | |
60 | executable projects: most functionality is in a library crate, and the binary | |
61 | crate uses that library crate. As a result, other programs can also use the | |
62 | library crate, and it’s a nice separation of concerns. | |
63 | ||
64 | From the point of view of a crate outside the `communicator` library looking | |
65 | in, all the modules we’ve been creating are within a module that has the same | |
66 | name as the crate, `communicator`. We call the top-level module of a crate the | |
67 | *root module*. | |
68 | ||
69 | Also note that even if we’re using an external crate within a submodule of our | |
cc61c64b XL |
70 | project, the `extern crate` should go in our root module (so in *src/main.rs* |
71 | or *src/lib.rs*). Then, in our submodules, we can refer to items from external | |
72 | crates as if the items are top-level modules. | |
73 | ||
7cac9316 XL |
74 | Right now, our binary crate just calls our library’s `connect` function from |
75 | the `client` module. However, invoking `cargo build` will now give us an error | |
cc61c64b XL |
76 | after the warnings: |
77 | ||
78 | ```text | |
abe05a73 | 79 | error[E0603]: module `client` is private |
cc61c64b XL |
80 | --> src/main.rs:4:5 |
81 | | | |
82 | 4 | communicator::client::connect(); | |
83 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
84 | ``` | |
85 | ||
7cac9316 XL |
86 | Ah ha! This error tells us that the `client` module is private, which is the |
87 | crux of the warnings. It’s also the first time we’ve run into the concepts of | |
cc61c64b XL |
88 | *public* and *private* in the context of Rust. The default state of all code in |
89 | Rust is private: no one else is allowed to use the code. If you don’t use a | |
7cac9316 XL |
90 | private function within your program, because your program is the only code |
91 | allowed to use that function, Rust will warn you that the function has gone | |
92 | unused. | |
93 | ||
94 | After we specify that a function like `client::connect` is public, not only | |
95 | will our call to that function from our binary crate be allowed, but the | |
96 | warning that the function is unused will go away. Marking a function as public | |
97 | lets Rust know that the function will be used by code outside of our program. | |
98 | Rust considers the theoretical external usage that’s now possible as the | |
abe05a73 XL |
99 | function “being used.” Thus, when a function is marked public, Rust will not |
100 | require that it be used in our program and will stop warning that the function | |
101 | is unused. | |
cc61c64b XL |
102 | |
103 | ### Making a Function Public | |
104 | ||
abe05a73 XL |
105 | To tell Rust to make a function public, we add the `pub` keyword to the start |
106 | of the declaration. We’ll focus on fixing the warning that indicates | |
107 | `client::connect` has gone unused for now, as well as the `` module `client` is | |
108 | private `` error from our binary crate. Modify *src/lib.rs* to make the | |
109 | `client` module public, like so: | |
cc61c64b XL |
110 | |
111 | <span class="filename">Filename: src/lib.rs</span> | |
112 | ||
113 | ```rust,ignore | |
114 | pub mod client; | |
115 | ||
116 | mod network; | |
117 | ``` | |
118 | ||
7cac9316 | 119 | The `pub` keyword is placed right before `mod`. Let’s try building again: |
cc61c64b XL |
120 | |
121 | ```text | |
abe05a73 | 122 | error[E0603]: function `connect` is private |
cc61c64b XL |
123 | --> src/main.rs:4:5 |
124 | | | |
125 | 4 | communicator::client::connect(); | |
126 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
127 | ``` | |
128 | ||
129 | Hooray! We have a different error! Yes, different error messages are a cause | |
7cac9316 XL |
130 | for celebration. The new error shows `` function `connect` is private ``, so |
131 | let’s edit *src/client.rs* to make `client::connect` public too: | |
cc61c64b XL |
132 | |
133 | <span class="filename">Filename: src/client.rs</span> | |
134 | ||
135 | ```rust | |
136 | pub fn connect() { | |
137 | } | |
138 | ``` | |
139 | ||
7cac9316 | 140 | Now run `cargo build` again: |
cc61c64b XL |
141 | |
142 | ```text | |
abe05a73 | 143 | warning: function is never used: `connect` |
cc61c64b XL |
144 | --> src/network/mod.rs:1:1 |
145 | | | |
abe05a73 XL |
146 | 1 | / fn connect() { |
147 | 2 | | } | |
148 | | |_^ | |
149 | | | |
150 | = note: #[warn(dead_code)] on by default | |
cc61c64b | 151 | |
abe05a73 | 152 | warning: function is never used: `connect` |
cc61c64b XL |
153 | --> src/network/server.rs:1:1 |
154 | | | |
abe05a73 XL |
155 | 1 | / fn connect() { |
156 | 2 | | } | |
157 | | |_^ | |
cc61c64b XL |
158 | ``` |
159 | ||
7cac9316 XL |
160 | The code compiled, and the warning about `client::connect` not being used is |
161 | gone! | |
cc61c64b | 162 | |
7cac9316 XL |
163 | Unused code warnings don’t always indicate that an item in your code needs to |
164 | be made public: if you *didn’t* want these functions to be part of your public | |
165 | API, unused code warnings could be alerting you to code you no longer need that | |
166 | you can safely delete. They could also be alerting you to a bug if you had just | |
cc61c64b XL |
167 | accidentally removed all places within your library where this function is |
168 | called. | |
169 | ||
7cac9316 XL |
170 | But in this case, we *do* want the other two functions to be part of our |
171 | crate’s public API, so let’s mark them as `pub` as well to get rid of the | |
172 | remaining warnings. Modify *src/network/mod.rs* to look like the following: | |
cc61c64b XL |
173 | |
174 | <span class="filename">Filename: src/network/mod.rs</span> | |
175 | ||
176 | ```rust,ignore | |
177 | pub fn connect() { | |
178 | } | |
179 | ||
180 | mod server; | |
181 | ``` | |
182 | ||
7cac9316 | 183 | Then compile the code: |
cc61c64b XL |
184 | |
185 | ```text | |
abe05a73 | 186 | warning: function is never used: `connect` |
cc61c64b XL |
187 | --> src/network/mod.rs:1:1 |
188 | | | |
abe05a73 XL |
189 | 1 | / pub fn connect() { |
190 | 2 | | } | |
191 | | |_^ | |
192 | | | |
193 | = note: #[warn(dead_code)] on by default | |
cc61c64b | 194 | |
abe05a73 | 195 | warning: function is never used: `connect` |
cc61c64b XL |
196 | --> src/network/server.rs:1:1 |
197 | | | |
abe05a73 XL |
198 | 1 | / fn connect() { |
199 | 2 | | } | |
200 | | |_^ | |
cc61c64b XL |
201 | ``` |
202 | ||
7cac9316 XL |
203 | Hmmm, we’re still getting an unused function warning, even though |
204 | `network::connect` is set to `pub`. The reason is that the function is public | |
cc61c64b | 205 | within the module, but the `network` module that the function resides in is not |
7cac9316 | 206 | public. We’re working from the interior of the library out this time, whereas |
cc61c64b | 207 | with `client::connect` we worked from the outside in. We need to change |
7cac9316 | 208 | *src/lib.rs* to make `network` public too, like so: |
cc61c64b XL |
209 | |
210 | <span class="filename">Filename: src/lib.rs</span> | |
211 | ||
212 | ```rust,ignore | |
213 | pub mod client; | |
214 | ||
215 | pub mod network; | |
216 | ``` | |
217 | ||
7cac9316 | 218 | Now when we compile, that warning is gone: |
cc61c64b XL |
219 | |
220 | ```text | |
abe05a73 | 221 | warning: function is never used: `connect` |
cc61c64b XL |
222 | --> src/network/server.rs:1:1 |
223 | | | |
abe05a73 XL |
224 | 1 | / fn connect() { |
225 | 2 | | } | |
226 | | |_^ | |
227 | | | |
228 | = note: #[warn(dead_code)] on by default | |
cc61c64b XL |
229 | ``` |
230 | ||
7cac9316 | 231 | Only one warning is left! Try to fix this one on your own! |
cc61c64b XL |
232 | |
233 | ### Privacy Rules | |
234 | ||
235 | Overall, these are the rules for item visibility: | |
236 | ||
237 | 1. If an item is public, it can be accessed through any of its parent modules. | |
3b2f2976 XL |
238 | 2. If an item is private, it can be accessed only by its immediate parent |
239 | module and any of the parent’s child modules. | |
cc61c64b XL |
240 | |
241 | ### Privacy Examples | |
242 | ||
7cac9316 XL |
243 | Let’s look at a few more privacy examples to get some practice. Create a new |
244 | library project and enter the code in Listing 7-5 into your new project’s | |
245 | *src/lib.rs*: | |
cc61c64b XL |
246 | |
247 | <span class="filename">Filename: src/lib.rs</span> | |
248 | ||
249 | ```rust,ignore | |
250 | mod outermost { | |
251 | pub fn middle_function() {} | |
252 | ||
253 | fn middle_secret_function() {} | |
254 | ||
255 | mod inside { | |
256 | pub fn inner_function() {} | |
257 | ||
258 | fn secret_function() {} | |
259 | } | |
260 | } | |
261 | ||
262 | fn try_me() { | |
263 | outermost::middle_function(); | |
264 | outermost::middle_secret_function(); | |
265 | outermost::inside::inner_function(); | |
266 | outermost::inside::secret_function(); | |
267 | } | |
268 | ``` | |
269 | ||
270 | <span class="caption">Listing 7-5: Examples of private and public functions, | |
271 | some of which are incorrect</span> | |
272 | ||
7cac9316 XL |
273 | Before you try to compile this code, make a guess about which lines in the |
274 | `try_me` function will have errors. Then, try compiling the code to see whether | |
275 | you were right, and read on for the discussion of the errors! | |
cc61c64b XL |
276 | |
277 | #### Looking at the Errors | |
278 | ||
279 | The `try_me` function is in the root module of our project. The module named | |
7cac9316 XL |
280 | `outermost` is private, but the second privacy rule states that the `try_me` |
281 | function is allowed to access the `outermost` module because `outermost` is in | |
282 | the current (root) module, as is `try_me`. | |
cc61c64b | 283 | |
7cac9316 XL |
284 | The call to `outermost::middle_function` will work because `middle_function` is |
285 | public, and `try_me` is accessing `middle_function` through its parent module | |
286 | `outermost`. We determined in the previous paragraph that this module is | |
287 | accessible. | |
cc61c64b XL |
288 | |
289 | The call to `outermost::middle_secret_function` will cause a compilation error. | |
290 | `middle_secret_function` is private, so the second rule applies. The root | |
291 | module is neither the current module of `middle_secret_function` (`outermost` | |
292 | is), nor is it a child module of the current module of `middle_secret_function`. | |
293 | ||
294 | The module named `inside` is private and has no child modules, so it can only | |
7cac9316 XL |
295 | be accessed by its current module `outermost`. That means the `try_me` function |
296 | is not allowed to call `outermost::inside::inner_function` or | |
297 | `outermost::inside::secret_function`. | |
cc61c64b XL |
298 | |
299 | #### Fixing the Errors | |
300 | ||
301 | Here are some suggestions for changing the code in an attempt to fix the | |
302 | errors. Before you try each one, make a guess as to whether it will fix the | |
7cac9316 XL |
303 | errors, and then compile the code to see whether or not you’re right, using the |
304 | privacy rules to understand why. | |
cc61c64b XL |
305 | |
306 | * What if the `inside` module was public? | |
307 | * What if `outermost` was public and `inside` was private? | |
308 | * What if, in the body of `inner_function`, you called | |
309 | `::outermost::middle_secret_function()`? (The two colons at the beginning mean | |
310 | that we want to refer to the modules starting from the root module.) | |
311 | ||
312 | Feel free to design more experiments and try them out! | |
313 | ||
7cac9316 | 314 | Next, let’s talk about bringing items into scope with the `use` keyword. |