]>
Commit | Line | Data |
---|---|---|
8bb4bdeb XL |
1 | # Visibility and Privacy |
2 | ||
3b2f2976 XL |
3 | > **<sup>Syntax<sup>** |
4 | > _Visibility_ : | |
5 | > EMPTY | |
6 | > | `pub` | |
7 | > | `pub` `(` `crate` `)` | |
8 | > | `pub` `(` `in` _ModulePath_ `)` | |
9 | > | `pub` `(` `in`<sup>?</sup> `self` `)` | |
10 | > | `pub` `(` `in`<sup>?</sup> `super` `)` | |
11 | ||
8bb4bdeb XL |
12 | These two terms are often used interchangeably, and what they are attempting to |
13 | convey is the answer to the question "Can this item be used at this location?" | |
14 | ||
15 | Rust's name resolution operates on a global hierarchy of namespaces. Each level | |
16 | in the hierarchy can be thought of as some item. The items are one of those | |
17 | mentioned above, but also include external crates. Declaring or defining a new | |
18 | module can be thought of as inserting a new tree into the hierarchy at the | |
19 | location of the definition. | |
20 | ||
21 | To control whether interfaces can be used across modules, Rust checks each use | |
22 | of an item to see whether it should be allowed or not. This is where privacy | |
23 | warnings are generated, or otherwise "you used a private item of another module | |
24 | and weren't allowed to." | |
25 | ||
26 | By default, everything in Rust is *private*, with two exceptions: Associated | |
27 | items in a `pub` Trait are public by default; Enum variants | |
28 | in a `pub` enum are also public by default. When an item is declared as `pub`, | |
29 | it can be thought of as being accessible to the outside world. For example: | |
30 | ||
cc61c64b | 31 | ```rust |
8bb4bdeb XL |
32 | # fn main() {} |
33 | // Declare a private struct | |
34 | struct Foo; | |
35 | ||
36 | // Declare a public struct with a private field | |
37 | pub struct Bar { | |
38 | field: i32, | |
39 | } | |
40 | ||
41 | // Declare a public enum with two public variants | |
42 | pub enum State { | |
43 | PubliclyAccessibleState, | |
44 | PubliclyAccessibleState2, | |
45 | } | |
46 | ``` | |
47 | ||
48 | With the notion of an item being either public or private, Rust allows item | |
49 | accesses in two cases: | |
50 | ||
cc61c64b XL |
51 | 1. If an item is public, then it can be accessed externally from some module |
52 | `m` if you can access all the item's parent modules from `m`. You can | |
53 | also potentially be able to name the item through re-exports. See below. | |
8bb4bdeb XL |
54 | 2. If an item is private, it may be accessed by the current module and its |
55 | descendants. | |
56 | ||
57 | These two cases are surprisingly powerful for creating module hierarchies | |
58 | exposing public APIs while hiding internal implementation details. To help | |
59 | explain, here's a few use cases and what they would entail: | |
60 | ||
61 | * A library developer needs to expose functionality to crates which link | |
62 | against their library. As a consequence of the first case, this means that | |
63 | anything which is usable externally must be `pub` from the root down to the | |
64 | destination item. Any private item in the chain will disallow external | |
65 | accesses. | |
66 | ||
67 | * A crate needs a global available "helper module" to itself, but it doesn't | |
68 | want to expose the helper module as a public API. To accomplish this, the | |
69 | root of the crate's hierarchy would have a private module which then | |
70 | internally has a "public API". Because the entire crate is a descendant of | |
71 | the root, then the entire local crate can access this private module through | |
72 | the second case. | |
73 | ||
74 | * When writing unit tests for a module, it's often a common idiom to have an | |
75 | immediate child of the module to-be-tested named `mod test`. This module | |
76 | could access any items of the parent module through the second case, meaning | |
77 | that internal implementation details could also be seamlessly tested from the | |
78 | child module. | |
79 | ||
80 | In the second case, it mentions that a private item "can be accessed" by the | |
81 | current module and its descendants, but the exact meaning of accessing an item | |
82 | depends on what the item is. Accessing a module, for example, would mean | |
83 | looking inside of it (to import more items). On the other hand, accessing a | |
84 | function would mean that it is invoked. Additionally, path expressions and | |
85 | import statements are considered to access an item in the sense that the | |
86 | import/expression is only valid if the destination is in the current visibility | |
87 | scope. | |
88 | ||
89 | Here's an example of a program which exemplifies the three cases outlined | |
90 | above: | |
91 | ||
cc61c64b | 92 | ```rust |
8bb4bdeb XL |
93 | // This module is private, meaning that no external crate can access this |
94 | // module. Because it is private at the root of this current crate, however, any | |
95 | // module in the crate may access any publicly visible item in this module. | |
96 | mod crate_helper_module { | |
97 | ||
98 | // This function can be used by anything in the current crate | |
99 | pub fn crate_helper() {} | |
100 | ||
101 | // This function *cannot* be used by anything else in the crate. It is not | |
102 | // publicly visible outside of the `crate_helper_module`, so only this | |
103 | // current module and its descendants may access it. | |
104 | fn implementation_detail() {} | |
105 | } | |
106 | ||
107 | // This function is "public to the root" meaning that it's available to external | |
108 | // crates linking against this one. | |
109 | pub fn public_api() {} | |
110 | ||
111 | // Similarly to 'public_api', this module is public so external crates may look | |
112 | // inside of it. | |
113 | pub mod submodule { | |
114 | use crate_helper_module; | |
115 | ||
116 | pub fn my_method() { | |
117 | // Any item in the local crate may invoke the helper module's public | |
118 | // interface through a combination of the two rules above. | |
119 | crate_helper_module::crate_helper(); | |
120 | } | |
121 | ||
122 | // This function is hidden to any module which is not a descendant of | |
123 | // `submodule` | |
124 | fn my_implementation() {} | |
125 | ||
126 | #[cfg(test)] | |
127 | mod test { | |
128 | ||
129 | #[test] | |
130 | fn test_my_implementation() { | |
131 | // Because this module is a descendant of `submodule`, it's allowed | |
132 | // to access private items inside of `submodule` without a privacy | |
133 | // violation. | |
134 | super::my_implementation(); | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
139 | # fn main() {} | |
140 | ``` | |
141 | ||
142 | For a Rust program to pass the privacy checking pass, all paths must be valid | |
143 | accesses given the two rules above. This includes all use statements, | |
144 | expressions, types, etc. | |
145 | ||
cc61c64b XL |
146 | ## `pub(in path)`, `pub(crate)`, `pub(super)`, and `pub(self)` |
147 | ||
148 | In addition to public and private, Rust allows users to declare an item as | |
149 | visible within a given scope. The rules for `pub` restrictions are as follows: | |
150 | - `pub(in path)` makes an item visible within the provided `path`. `path` must | |
151 | be a parent module of the item whose visibility is being declared. | |
152 | - `pub(crate)` makes an item visible within the current crate. | |
94b46f34 XL |
153 | - `pub(super)` makes an item visible to the parent module. This is equivalent |
154 | to `pub(in super)`. | |
cc61c64b XL |
155 | - `pub(self)` makes an item visible to the current module. This is equivalent |
156 | to `pub(in self)`. | |
157 | ||
158 | Here's an example: | |
159 | ||
160 | ```rust | |
161 | pub mod outer_mod { | |
162 | pub mod inner_mod { | |
163 | // This function is visible within `outer_mod` | |
164 | pub(in outer_mod) fn outer_mod_visible_fn() {} | |
165 | ||
166 | // This function is visible to the entire crate | |
167 | pub(crate) fn crate_visible_fn() {} | |
168 | ||
169 | // This function is visible within `outer_mod` | |
170 | pub(super) fn super_mod_visible_fn() { | |
171 | // This function is visible since we're in the same `mod` | |
172 | inner_mod_visible_fn(); | |
173 | } | |
174 | ||
175 | // This function is visible | |
176 | pub(self) fn inner_mod_visible_fn() {} | |
177 | } | |
178 | pub fn foo() { | |
179 | inner_mod::outer_mod_visible_fn(); | |
180 | inner_mod::crate_visible_fn(); | |
181 | inner_mod::super_mod_visible_fn(); | |
182 | ||
183 | // This function is no longer visible since we're outside of `inner_mod` | |
184 | // Error! `inner_mod_visible_fn` is private | |
185 | //inner_mod::inner_mod_visible_fn(); | |
186 | } | |
187 | } | |
188 | ||
189 | fn bar() { | |
190 | // This function is still visible since we're in the same crate | |
191 | outer_mod::inner_mod::crate_visible_fn(); | |
192 | ||
193 | // This function is no longer visible since we're outside of `outer_mod` | |
194 | // Error! `super_mod_visible_fn` is private | |
195 | //outer_mod::inner_mod::super_mod_visible_fn(); | |
196 | ||
197 | // This function is no longer visible since we're outside of `outer_mod` | |
198 | // Error! `outer_mod_visible_fn` is private | |
199 | //outer_mod::inner_mod::outer_mod_visible_fn(); | |
200 | ||
201 | outer_mod::foo(); | |
202 | } | |
203 | ||
204 | fn main() { bar() } | |
205 | ``` | |
206 | ||
8bb4bdeb XL |
207 | ## Re-exporting and Visibility |
208 | ||
209 | Rust allows publicly re-exporting items through a `pub use` directive. Because | |
210 | this is a public directive, this allows the item to be used in the current | |
211 | module through the rules above. It essentially allows public access into the | |
212 | re-exported item. For example, this program is valid: | |
213 | ||
cc61c64b | 214 | ```rust |
8bb4bdeb XL |
215 | pub use self::implementation::api; |
216 | ||
217 | mod implementation { | |
218 | pub mod api { | |
219 | pub fn f() {} | |
220 | } | |
221 | } | |
222 | ||
223 | # fn main() {} | |
224 | ``` | |
225 | ||
226 | This means that any external crate referencing `implementation::api::f` would | |
227 | receive a privacy violation, while the path `api::f` would be allowed. | |
228 | ||
229 | When re-exporting a private item, it can be thought of as allowing the "privacy | |
230 | chain" being short-circuited through the reexport instead of passing through | |
231 | the namespace hierarchy as it normally would. |