]>
Commit | Line | Data |
---|---|---|
9346a6ac AL |
1 | % Structs |
2 | ||
bd371182 | 3 | Structs are a way of creating more complex data types. For example, if we were |
9346a6ac AL |
4 | doing calculations involving coordinates in 2D space, we would need both an `x` |
5 | and a `y` value: | |
6 | ||
7 | ```rust | |
8 | let origin_x = 0; | |
9 | let origin_y = 0; | |
10 | ``` | |
11 | ||
12 | A struct lets us combine these two into a single, unified datatype: | |
13 | ||
14 | ```rust | |
15 | struct Point { | |
16 | x: i32, | |
17 | y: i32, | |
18 | } | |
19 | ||
20 | fn main() { | |
21 | let origin = Point { x: 0, y: 0 }; // origin: Point | |
22 | ||
23 | println!("The origin is at ({}, {})", origin.x, origin.y); | |
24 | } | |
25 | ``` | |
26 | ||
bd371182 AL |
27 | There’s a lot going on here, so let’s break it down. We declare a `struct` with |
28 | the `struct` keyword, and then with a name. By convention, `struct`s begin with | |
29 | a capital letter and are camel cased: `PointInSpace`, not `Point_In_Space`. | |
9346a6ac AL |
30 | |
31 | We can create an instance of our struct via `let`, as usual, but we use a `key: | |
bd371182 | 32 | value` style syntax to set each field. The order doesn’t need to be the same as |
9346a6ac AL |
33 | in the original declaration. |
34 | ||
35 | Finally, because fields have names, we can access the field through dot | |
36 | notation: `origin.x`. | |
37 | ||
38 | The values in structs are immutable by default, like other bindings in Rust. | |
39 | Use `mut` to make them mutable: | |
40 | ||
41 | ```rust | |
42 | struct Point { | |
43 | x: i32, | |
44 | y: i32, | |
45 | } | |
46 | ||
47 | fn main() { | |
48 | let mut point = Point { x: 0, y: 0 }; | |
49 | ||
50 | point.x = 5; | |
51 | ||
52 | println!("The point is at ({}, {})", point.x, point.y); | |
53 | } | |
54 | ``` | |
55 | ||
56 | This will print `The point is at (5, 0)`. | |
57 | ||
58 | Rust does not support field mutability at the language level, so you cannot | |
59 | write something like this: | |
60 | ||
61 | ```rust,ignore | |
62 | struct Point { | |
63 | mut x: i32, | |
64 | y: i32, | |
65 | } | |
66 | ``` | |
67 | ||
68 | Mutability is a property of the binding, not of the structure itself. If you’re | |
69 | used to field-level mutability, this may seem strange at first, but it | |
70 | significantly simplifies things. It even lets you make things mutable for a short | |
71 | time only: | |
72 | ||
73 | ||
74 | ```rust,ignore | |
75 | struct Point { | |
76 | x: i32, | |
77 | y: i32, | |
78 | } | |
79 | ||
80 | fn main() { | |
81 | let mut point = Point { x: 0, y: 0 }; | |
82 | ||
83 | point.x = 5; | |
84 | ||
85 | let point = point; // this new binding can’t change now | |
86 | ||
87 | point.y = 6; // this causes an error | |
88 | } | |
89 | ``` | |
bd371182 AL |
90 | |
91 | # Update syntax | |
92 | ||
93 | A `struct` can include `..` to indicate that you want to use a copy of some | |
94 | other struct for some of the values. For example: | |
95 | ||
96 | ```rust | |
97 | struct Point3d { | |
98 | x: i32, | |
99 | y: i32, | |
100 | z: i32, | |
101 | } | |
102 | ||
103 | let mut point = Point3d { x: 0, y: 0, z: 0 }; | |
104 | point = Point3d { y: 1, .. point }; | |
105 | ``` | |
106 | ||
107 | This gives `point` a new `y`, but keeps the old `x` and `z` values. It doesn’t | |
108 | have to be the same `struct` either, you can use this syntax when making new | |
109 | ones, and it will copy the values you don’t specify: | |
110 | ||
111 | ```rust | |
112 | # struct Point3d { | |
113 | # x: i32, | |
114 | # y: i32, | |
115 | # z: i32, | |
116 | # } | |
117 | let origin = Point3d { x: 0, y: 0, z: 0 }; | |
118 | let point = Point3d { z: 1, x: 2, .. origin }; | |
119 | ``` | |
120 | ||
121 | # Tuple structs | |
122 | ||
123 | Rust has another data type that’s like a hybrid between a [tuple][tuple] and a | |
124 | struct, called a ‘tuple struct’. Tuple structs have a name, but | |
125 | their fields don’t: | |
126 | ||
127 | ```rust | |
128 | struct Color(i32, i32, i32); | |
129 | struct Point(i32, i32, i32); | |
130 | ``` | |
131 | ||
132 | [tuple]: primitive-types.html#tuples | |
133 | ||
134 | These two will not be equal, even if they have the same values: | |
135 | ||
136 | ```rust | |
137 | # struct Color(i32, i32, i32); | |
138 | # struct Point(i32, i32, i32); | |
139 | let black = Color(0, 0, 0); | |
140 | let origin = Point(0, 0, 0); | |
141 | ``` | |
142 | ||
143 | It is almost always better to use a struct than a tuple struct. We would write | |
144 | `Color` and `Point` like this instead: | |
145 | ||
146 | ```rust | |
147 | struct Color { | |
148 | red: i32, | |
149 | blue: i32, | |
150 | green: i32, | |
151 | } | |
152 | ||
153 | struct Point { | |
154 | x: i32, | |
155 | y: i32, | |
156 | z: i32, | |
157 | } | |
158 | ``` | |
159 | ||
160 | Now, we have actual names, rather than positions. Good names are important, | |
161 | and with a struct, we have actual names. | |
162 | ||
163 | There _is_ one case when a tuple struct is very useful, though, and that’s a | |
164 | tuple struct with only one element. We call this the ‘newtype’ pattern, because | |
165 | it allows you to create a new type, distinct from that of its contained value | |
166 | and expressing its own semantic meaning: | |
167 | ||
168 | ```rust | |
169 | struct Inches(i32); | |
170 | ||
171 | let length = Inches(10); | |
172 | ||
173 | let Inches(integer_length) = length; | |
174 | println!("length is {} inches", integer_length); | |
175 | ``` | |
176 | ||
177 | As you can see here, you can extract the inner integer type through a | |
178 | destructuring `let`, just as with regular tuples. In this case, the | |
179 | `let Inches(integer_length)` assigns `10` to `integer_length`. | |
180 | ||
181 | # Unit-like structs | |
182 | ||
183 | You can define a struct with no members at all: | |
184 | ||
185 | ```rust | |
186 | struct Electron; | |
187 | ``` | |
188 | ||
189 | Such a struct is called ‘unit-like’ because it resembles the empty | |
190 | tuple, `()`, sometimes called ‘unit’. Like a tuple struct, it defines a | |
191 | new type. | |
192 | ||
193 | This is rarely useful on its own (although sometimes it can serve as a | |
194 | marker type), but in combination with other features, it can become | |
195 | useful. For instance, a library may ask you to create a structure that | |
196 | implements a certain [trait][trait] to handle events. If you don’t have | |
197 | any data you need to store in the structure, you can just create a | |
198 | unit-like struct. | |
d9579d0f AL |
199 | |
200 | [trait]: traits.html |