]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Defining and Instantiating Structs |
2 | ||
a2a8927a XL |
3 | Structs are similar to tuples, discussed in [“The Tuple Type”][tuples]<!-- |
4 | ignore --> section, in that both hold multiple related values. Like tuples, the | |
5 | pieces of a struct can be different types. Unlike with tuples, in a struct | |
6 | you’ll name each piece of data so it’s clear what the values mean. Adding these | |
7 | names means that structs are more flexible than tuples: you don’t have to rely | |
8 | on the order of the data to specify or access the values of an instance. | |
13cf67c4 XL |
9 | |
10 | To define a struct, we enter the keyword `struct` and name the entire struct. A | |
11 | struct’s name should describe the significance of the pieces of data being | |
12 | grouped together. Then, inside curly brackets, we define the names and types of | |
13 | the pieces of data, which we call *fields*. For example, Listing 5-1 shows a | |
69743fb6 | 14 | struct that stores information about a user account. |
13cf67c4 XL |
15 | |
16 | ```rust | |
74b04a01 | 17 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs:here}} |
13cf67c4 XL |
18 | ``` |
19 | ||
20 | <span class="caption">Listing 5-1: A `User` struct definition</span> | |
21 | ||
22 | To use a struct after we’ve defined it, we create an *instance* of that struct | |
23 | by specifying concrete values for each of the fields. We create an instance by | |
24 | stating the name of the struct and then add curly brackets containing `key: | |
25 | value` pairs, where the keys are the names of the fields and the values are the | |
26 | data we want to store in those fields. We don’t have to specify the fields in | |
27 | the same order in which we declared them in the struct. In other words, the | |
28 | struct definition is like a general template for the type, and instances fill | |
29 | in that template with particular data to create values of the type. For | |
69743fb6 | 30 | example, we can declare a particular user as shown in Listing 5-2. |
13cf67c4 XL |
31 | |
32 | ```rust | |
74b04a01 | 33 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs:here}} |
13cf67c4 XL |
34 | ``` |
35 | ||
36 | <span class="caption">Listing 5-2: Creating an instance of the `User` | |
37 | struct</span> | |
38 | ||
923072b8 FG |
39 | To get a specific value from a struct, we use dot notation. For example, to |
40 | access this user’s email address, we use `user1.email`. If the instance is | |
41 | mutable, we can change a value by using the dot notation and assigning into a | |
42 | particular field. Listing 5-3 shows how to change the value in the `email` | |
43 | field of a mutable `User` instance. | |
13cf67c4 XL |
44 | |
45 | ```rust | |
74b04a01 | 46 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs:here}} |
13cf67c4 XL |
47 | ``` |
48 | ||
49 | <span class="caption">Listing 5-3: Changing the value in the `email` field of a | |
50 | `User` instance</span> | |
51 | ||
52 | Note that the entire instance must be mutable; Rust doesn’t allow us to mark | |
69743fb6 XL |
53 | only certain fields as mutable. As with any expression, we can construct a new |
54 | instance of the struct as the last expression in the function body to | |
55 | implicitly return that new instance. | |
13cf67c4 | 56 | |
13cf67c4 XL |
57 | Listing 5-4 shows a `build_user` function that returns a `User` instance with |
58 | the given email and username. The `active` field gets the value of `true`, and | |
59 | the `sign_in_count` gets a value of `1`. | |
60 | ||
61 | ```rust | |
74b04a01 | 62 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs:here}} |
13cf67c4 XL |
63 | ``` |
64 | ||
65 | <span class="caption">Listing 5-4: A `build_user` function that takes an email | |
66 | and username and returns a `User` instance</span> | |
67 | ||
68 | It makes sense to name the function parameters with the same name as the struct | |
69 | fields, but having to repeat the `email` and `username` field names and | |
70 | variables is a bit tedious. If the struct had more fields, repeating each name | |
71 | would get even more annoying. Luckily, there’s a convenient shorthand! | |
72 | ||
a2a8927a XL |
73 | <a id="using-the-field-init-shorthand-when-variables-and-fields-have-the-same-name"></a> |
74 | ### Using the Field Init Shorthand | |
13cf67c4 XL |
75 | |
76 | Because the parameter names and the struct field names are exactly the same in | |
77 | Listing 5-4, we can use the *field init shorthand* syntax to rewrite | |
78 | `build_user` so that it behaves exactly the same but doesn’t have the | |
69743fb6 | 79 | repetition of `email` and `username`, as shown in Listing 5-5. |
13cf67c4 XL |
80 | |
81 | ```rust | |
74b04a01 | 82 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs:here}} |
13cf67c4 XL |
83 | ``` |
84 | ||
85 | <span class="caption">Listing 5-5: A `build_user` function that uses field init | |
86 | shorthand because the `email` and `username` parameters have the same name as | |
87 | struct fields</span> | |
88 | ||
89 | Here, we’re creating a new instance of the `User` struct, which has a field | |
90 | named `email`. We want to set the `email` field’s value to the value in the | |
91 | `email` parameter of the `build_user` function. Because the `email` field and | |
92 | the `email` parameter have the same name, we only need to write `email` rather | |
93 | than `email: email`. | |
94 | ||
95 | ### Creating Instances From Other Instances With Struct Update Syntax | |
96 | ||
a2a8927a XL |
97 | It’s often useful to create a new instance of a struct that includes most of |
98 | the values from another instance, but changes some. You can do this using | |
99 | *struct update syntax*. | |
13cf67c4 | 100 | |
a2a8927a XL |
101 | First, in Listing 5-6 we show how to create a new `User` instance in `user2` |
102 | regularly, without the update syntax. We set a new value for `email` but | |
103 | otherwise use the same values from `user1` that we created in Listing 5-2. | |
13cf67c4 XL |
104 | |
105 | ```rust | |
74b04a01 | 106 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs:here}} |
13cf67c4 XL |
107 | ``` |
108 | ||
94222f64 | 109 | <span class="caption">Listing 5-6: Creating a new `User` instance using one of |
13cf67c4 XL |
110 | the values from `user1`</span> |
111 | ||
112 | Using struct update syntax, we can achieve the same effect with less code, as | |
113 | shown in Listing 5-7. The syntax `..` specifies that the remaining fields not | |
114 | explicitly set should have the same value as the fields in the given instance. | |
115 | ||
116 | ```rust | |
74b04a01 | 117 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs:here}} |
13cf67c4 XL |
118 | ``` |
119 | ||
94222f64 XL |
120 | <span class="caption">Listing 5-7: Using struct update syntax to set a new |
121 | `email` value for a `User` instance but use the rest of the values from | |
122 | `user1`</span> | |
13cf67c4 XL |
123 | |
124 | The code in Listing 5-7 also creates an instance in `user2` that has a | |
94222f64 XL |
125 | different value for `email` but has the same values for the `username`, |
126 | `active`, and `sign_in_count` fields from `user1`. The `..user1` must come last | |
127 | to specify that any remaining fields should get their values from the | |
128 | corresponding fields in `user1`, but we can choose to specify values for as | |
129 | many fields as we want in any order, regardless of the order of the fields in | |
130 | the struct’s definition. | |
131 | ||
a2a8927a XL |
132 | Note that the struct update syntax uses `=` like an assignment; this is |
133 | because it moves the data, just as we saw in the [“Ways Variables and Data | |
134 | Interact: Move”][move]<!-- ignore --> section. In this example, we can no | |
135 | longer use `user1` after creating `user2` because the `String` in the | |
136 | `username` field of `user1` was moved into `user2`. If we had given `user2` new | |
137 | `String` values for both `email` and `username`, and thus only used the | |
138 | `active` and `sign_in_count` values from `user1`, then `user1` would still be | |
139 | valid after creating `user2`. The types of `active` and `sign_in_count` are | |
140 | types that implement the `Copy` trait, so the behavior we discussed in the | |
141 | [“Stack-Only Data: Copy”][copy]<!-- ignore --> section would apply. | |
13cf67c4 | 142 | |
69743fb6 | 143 | ### Using Tuple Structs without Named Fields to Create Different Types |
13cf67c4 | 144 | |
a2a8927a | 145 | Rust also supports structs that look similar to tuples, called *tuple |
13cf67c4 XL |
146 | structs*. Tuple structs have the added meaning the struct name provides but |
147 | don’t have names associated with their fields; rather, they just have the types | |
148 | of the fields. Tuple structs are useful when you want to give the whole tuple a | |
a2a8927a | 149 | name and make the tuple a different type from other tuples, and when naming each |
13cf67c4 XL |
150 | field as in a regular struct would be verbose or redundant. |
151 | ||
69743fb6 | 152 | To define a tuple struct, start with the `struct` keyword and the struct name |
a2a8927a XL |
153 | followed by the types in the tuple. For example, here we define and use |
154 | two tuple structs named `Color` and `Point`: | |
13cf67c4 XL |
155 | |
156 | ```rust | |
a2a8927a | 157 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs}} |
13cf67c4 XL |
158 | ``` |
159 | ||
160 | Note that the `black` and `origin` values are different types, because they’re | |
161 | instances of different tuple structs. Each struct you define is its own type, | |
923072b8 FG |
162 | even though the fields within the struct might have the same types. For |
163 | example, a function that takes a parameter of type `Color` cannot take a | |
164 | `Point` as an argument, even though both types are made up of three `i32` | |
165 | values. Otherwise, tuple struct instances are similar to tuples in that you can | |
166 | destructure them into their individual pieces, and you can use a `.` followed | |
167 | by the index to access an individual value. | |
13cf67c4 XL |
168 | |
169 | ### Unit-Like Structs Without Any Fields | |
170 | ||
171 | You can also define structs that don’t have any fields! These are called | |
94222f64 XL |
172 | *unit-like structs* because they behave similarly to `()`, the unit type that |
173 | we mentioned in [“The Tuple Type”][tuples]<!-- ignore --> section. Unit-like | |
a2a8927a XL |
174 | structs can be useful when you need to implement a trait on some type but don’t |
175 | have any data that you want to store in the type itself. We’ll discuss traits | |
176 | in Chapter 10. Here’s an example of declaring and instantiating a unit struct | |
177 | named `AlwaysEqual`: | |
94222f64 XL |
178 | |
179 | ```rust | |
a2a8927a | 180 | {{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs}} |
94222f64 XL |
181 | ``` |
182 | ||
183 | To define `AlwaysEqual`, we use the `struct` keyword, the name we want, then a | |
184 | semicolon. No need for curly brackets or parentheses! Then we can get an | |
185 | instance of `AlwaysEqual` in the `subject` variable in a similar way: using the | |
a2a8927a XL |
186 | name we defined, without any curly brackets or parentheses. Imagine that later |
187 | we’ll implement behavior for this type such that every instance of | |
188 | `AlwaysEqual` is always equal to every instance of any other type, perhaps to | |
189 | have a known result for testing purposes. We wouldn’t need any data to | |
190 | implement that behavior! You’ll see in Chapter 10 how to define traits and | |
191 | implement them on any type, including unit-like structs. | |
13cf67c4 XL |
192 | |
193 | > ### Ownership of Struct Data | |
194 | > | |
195 | > In the `User` struct definition in Listing 5-1, we used the owned `String` | |
196 | > type rather than the `&str` string slice type. This is a deliberate choice | |
a2a8927a XL |
197 | > because we want each instance of this struct to own all of its data and for |
198 | > that data to be valid for as long as the entire struct is valid. | |
13cf67c4 | 199 | > |
a2a8927a XL |
200 | > It’s also possible for structs to store references to data owned by something |
201 | > else, but to do so requires the use of *lifetimes*, a Rust feature that we’ll | |
13cf67c4 XL |
202 | > discuss in Chapter 10. Lifetimes ensure that the data referenced by a struct |
203 | > is valid for as long as the struct is. Let’s say you try to store a reference | |
a2a8927a | 204 | > in a struct without specifying lifetimes, like the following; this won’t work: |
13cf67c4 XL |
205 | > |
206 | > <span class="filename">Filename: src/main.rs</span> | |
207 | > | |
74b04a01 XL |
208 | > <!-- CAN'T EXTRACT SEE https://github.com/rust-lang/mdBook/issues/1127 --> |
209 | > | |
13cf67c4 XL |
210 | > ```rust,ignore,does_not_compile |
211 | > struct User { | |
a2a8927a | 212 | > active: bool, |
13cf67c4 XL |
213 | > username: &str, |
214 | > email: &str, | |
215 | > sign_in_count: u64, | |
13cf67c4 XL |
216 | > } |
217 | > | |
218 | > fn main() { | |
219 | > let user1 = User { | |
220 | > email: "someone@example.com", | |
221 | > username: "someusername123", | |
222 | > active: true, | |
223 | > sign_in_count: 1, | |
224 | > }; | |
225 | > } | |
226 | > ``` | |
227 | > | |
228 | > The compiler will complain that it needs lifetime specifiers: | |
229 | > | |
f035d41b | 230 | > ```console |
74b04a01 XL |
231 | > $ cargo run |
232 | > Compiling structs v0.1.0 (file:///projects/structs) | |
13cf67c4 | 233 | > error[E0106]: missing lifetime specifier |
a2a8927a | 234 | > --> src/main.rs:3:15 |
13cf67c4 | 235 | > | |
a2a8927a | 236 | > 3 | username: &str, |
fc512014 XL |
237 | > | ^ expected named lifetime parameter |
238 | > | | |
239 | > help: consider introducing a named lifetime parameter | |
240 | > | | |
a2a8927a XL |
241 | > 1 ~ struct User<'a> { |
242 | > 2 | active: bool, | |
243 | > 3 ~ username: &'a str, | |
fc512014 | 244 | > | |
13cf67c4 XL |
245 | > |
246 | > error[E0106]: missing lifetime specifier | |
a2a8927a | 247 | > --> src/main.rs:4:12 |
13cf67c4 | 248 | > | |
a2a8927a | 249 | > 4 | email: &str, |
fc512014 XL |
250 | > | ^ expected named lifetime parameter |
251 | > | | |
252 | > help: consider introducing a named lifetime parameter | |
253 | > | | |
a2a8927a XL |
254 | > 1 ~ struct User<'a> { |
255 | > 2 | active: bool, | |
256 | > 3 | username: &str, | |
257 | > 4 ~ email: &'a str, | |
fc512014 | 258 | > | |
74b04a01 | 259 | > |
74b04a01 | 260 | > For more information about this error, try `rustc --explain E0106`. |
a2a8927a | 261 | > error: could not compile `structs` due to 2 previous errors |
13cf67c4 XL |
262 | > ``` |
263 | > | |
264 | > In Chapter 10, we’ll discuss how to fix these errors so you can store | |
265 | > references in structs, but for now, we’ll fix errors like these using owned | |
266 | > types like `String` instead of references like `&str`. | |
74b04a01 XL |
267 | |
268 | <!-- manual-regeneration | |
269 | for the error above | |
270 | after running update-rustc.sh: | |
271 | pbcopy < listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt | |
272 | paste above | |
273 | add `> ` before every line --> | |
94222f64 XL |
274 | |
275 | [tuples]: ch03-02-data-types.html#the-tuple-type | |
276 | [move]: ch04-01-what-is-ownership.html#ways-variables-and-data-interact-move | |
277 | [copy]: ch04-01-what-is-ownership.html#stack-only-data-copy |