]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch05-01-defining-structs.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / book / src / ch05-01-defining-structs.md
CommitLineData
13cf67c4
XL
1## Defining and Instantiating Structs
2
a2a8927a
XL
3Structs are similar to tuples, discussed in [“The Tuple Type”][tuples]<!--
4ignore --> section, in that both hold multiple related values. Like tuples, the
5pieces of a struct can be different types. Unlike with tuples, in a struct
6you’ll name each piece of data so it’s clear what the values mean. Adding these
7names means that structs are more flexible than tuples: you don’t have to rely
8on the order of the data to specify or access the values of an instance.
13cf67c4
XL
9
10To define a struct, we enter the keyword `struct` and name the entire struct. A
11struct’s name should describe the significance of the pieces of data being
12grouped together. Then, inside curly brackets, we define the names and types of
13the pieces of data, which we call *fields*. For example, Listing 5-1 shows a
69743fb6 14struct 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
22To use a struct after we’ve defined it, we create an *instance* of that struct
23by specifying concrete values for each of the fields. We create an instance by
24stating the name of the struct and then add curly brackets containing `key:
25value` pairs, where the keys are the names of the fields and the values are the
26data we want to store in those fields. We don’t have to specify the fields in
27the same order in which we declared them in the struct. In other words, the
28struct definition is like a general template for the type, and instances fill
29in that template with particular data to create values of the type. For
69743fb6 30example, 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`
37struct</span>
38
923072b8
FG
39To get a specific value from a struct, we use dot notation. For example, to
40access this user’s email address, we use `user1.email`. If the instance is
41mutable, we can change a value by using the dot notation and assigning into a
42particular field. Listing 5-3 shows how to change the value in the `email`
43field 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
52Note that the entire instance must be mutable; Rust doesn’t allow us to mark
69743fb6
XL
53only certain fields as mutable. As with any expression, we can construct a new
54instance of the struct as the last expression in the function body to
55implicitly return that new instance.
13cf67c4 56
13cf67c4
XL
57Listing 5-4 shows a `build_user` function that returns a `User` instance with
58the given email and username. The `active` field gets the value of `true`, and
59the `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
66and username and returns a `User` instance</span>
67
68It makes sense to name the function parameters with the same name as the struct
69fields, but having to repeat the `email` and `username` field names and
70variables is a bit tedious. If the struct had more fields, repeating each name
71would 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
76Because the parameter names and the struct field names are exactly the same in
77Listing 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 79repetition 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
86shorthand because the `email` and `username` parameters have the same name as
87struct fields</span>
88
89Here, we’re creating a new instance of the `User` struct, which has a field
90named `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
92the `email` parameter have the same name, we only need to write `email` rather
93than `email: email`.
94
95### Creating Instances From Other Instances With Struct Update Syntax
96
a2a8927a
XL
97It’s often useful to create a new instance of a struct that includes most of
98the values from another instance, but changes some. You can do this using
99*struct update syntax*.
13cf67c4 100
a2a8927a
XL
101First, in Listing 5-6 we show how to create a new `User` instance in `user2`
102regularly, without the update syntax. We set a new value for `email` but
103otherwise 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
110the values from `user1`</span>
111
112Using struct update syntax, we can achieve the same effect with less code, as
113shown in Listing 5-7. The syntax `..` specifies that the remaining fields not
114explicitly 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
124The code in Listing 5-7 also creates an instance in `user2` that has a
94222f64
XL
125different 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
127to specify that any remaining fields should get their values from the
128corresponding fields in `user1`, but we can choose to specify values for as
129many fields as we want in any order, regardless of the order of the fields in
130the struct’s definition.
131
a2a8927a
XL
132Note that the struct update syntax uses `=` like an assignment; this is
133because it moves the data, just as we saw in the [“Ways Variables and Data
134Interact: Move”][move]<!-- ignore --> section. In this example, we can no
135longer 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
139valid after creating `user2`. The types of `active` and `sign_in_count` are
140types 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 145Rust also supports structs that look similar to tuples, called *tuple
13cf67c4
XL
146structs*. Tuple structs have the added meaning the struct name provides but
147don’t have names associated with their fields; rather, they just have the types
148of the fields. Tuple structs are useful when you want to give the whole tuple a
a2a8927a 149name and make the tuple a different type from other tuples, and when naming each
13cf67c4
XL
150field as in a regular struct would be verbose or redundant.
151
69743fb6 152To define a tuple struct, start with the `struct` keyword and the struct name
a2a8927a
XL
153followed by the types in the tuple. For example, here we define and use
154two 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
160Note that the `black` and `origin` values are different types, because they’re
161instances of different tuple structs. Each struct you define is its own type,
923072b8
FG
162even though the fields within the struct might have the same types. For
163example, 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`
165values. Otherwise, tuple struct instances are similar to tuples in that you can
166destructure them into their individual pieces, and you can use a `.` followed
167by the index to access an individual value.
13cf67c4
XL
168
169### Unit-Like Structs Without Any Fields
170
171You 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
173we mentioned in [“The Tuple Type”][tuples]<!-- ignore --> section. Unit-like
a2a8927a
XL
174structs can be useful when you need to implement a trait on some type but don’t
175have any data that you want to store in the type itself. We’ll discuss traits
176in Chapter 10. Here’s an example of declaring and instantiating a unit struct
177named `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
183To define `AlwaysEqual`, we use the `struct` keyword, the name we want, then a
184semicolon. No need for curly brackets or parentheses! Then we can get an
185instance of `AlwaysEqual` in the `subject` variable in a similar way: using the
a2a8927a
XL
186name we defined, without any curly brackets or parentheses. Imagine that later
187we’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
189have a known result for testing purposes. We wouldn’t need any data to
190implement that behavior! You’ll see in Chapter 10 how to define traits and
191implement 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
269for the error above
270after running update-rustc.sh:
271pbcopy < listings/ch05-using-structs-to-structure-related-data/no-listing-02-reference-in-struct/output.txt
272paste above
273add `> ` 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