]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Data Types |
2 | ||
3 | Every value in Rust is of a certain *data type*, which tells Rust what kind of | |
4 | data is being specified so it knows how to work with that data. We’ll look at | |
5 | two data type subsets: scalar and compound. | |
6 | ||
7 | Keep in mind that Rust is a *statically typed* language, which means that it | |
8 | must know the types of all variables at compile time. The compiler can usually | |
9 | infer what type we want to use based on the value and how we use it. In cases | |
10 | when many types are possible, such as when we converted a `String` to a numeric | |
dc9dc135 XL |
11 | type using `parse` in the [“Comparing the Guess to the Secret |
12 | Number”][comparing-the-guess-to-the-secret-number]<!-- ignore --> section in | |
13 | Chapter 2, we must add a type annotation, like this: | |
13cf67c4 XL |
14 | |
15 | ```rust | |
16 | let guess: u32 = "42".parse().expect("Not a number!"); | |
17 | ``` | |
18 | ||
19 | If we don’t add the type annotation here, Rust will display the following | |
20 | error, which means the compiler needs more information from us to know which | |
21 | type we want to use: | |
22 | ||
f035d41b | 23 | ```console |
74b04a01 | 24 | {{#include ../listings/ch03-common-programming-concepts/output-only-01-no-type-annotations/output.txt}} |
13cf67c4 XL |
25 | ``` |
26 | ||
27 | You’ll see different type annotations for other data types. | |
28 | ||
29 | ### Scalar Types | |
30 | ||
31 | A *scalar* type represents a single value. Rust has four primary scalar types: | |
32 | integers, floating-point numbers, Booleans, and characters. You may recognize | |
33 | these from other programming languages. Let’s jump into how they work in Rust. | |
34 | ||
35 | #### Integer Types | |
36 | ||
37 | An *integer* is a number without a fractional component. We used one integer | |
38 | type in Chapter 2, the `u32` type. This type declaration indicates that the | |
39 | value it’s associated with should be an unsigned integer (signed integer types | |
40 | start with `i`, instead of `u`) that takes up 32 bits of space. Table 3-1 shows | |
41 | the built-in integer types in Rust. Each variant in the Signed and Unsigned | |
42 | columns (for example, `i16`) can be used to declare the type of an integer | |
43 | value. | |
44 | ||
45 | <span class="caption">Table 3-1: Integer Types in Rust</span> | |
46 | ||
47 | | Length | Signed | Unsigned | | |
48 | |---------|---------|----------| | |
49 | | 8-bit | `i8` | `u8` | | |
50 | | 16-bit | `i16` | `u16` | | |
51 | | 32-bit | `i32` | `u32` | | |
52 | | 64-bit | `i64` | `u64` | | |
53 | | 128-bit | `i128` | `u128` | | |
54 | | arch | `isize` | `usize` | | |
55 | ||
56 | Each variant can be either signed or unsigned and has an explicit size. | |
57 | *Signed* and *unsigned* refer to whether it’s possible for the number to be | |
3dfed10e | 58 | negative—in other words, whether the number needs to have a sign |
13cf67c4 XL |
59 | with it (signed) or whether it will only ever be positive and can therefore be |
60 | represented without a sign (unsigned). It’s like writing numbers on paper: when | |
61 | the sign matters, a number is shown with a plus sign or a minus sign; however, | |
62 | when it’s safe to assume the number is positive, it’s shown with no sign. | |
9fa01778 | 63 | Signed numbers are stored using [two’s complement](https://en.wikipedia.org/wiki/Two%27s_complement) representation. |
13cf67c4 XL |
64 | |
65 | Each signed variant can store numbers from -(2<sup>n - 1</sup>) to 2<sup>n - | |
66 | 1</sup> - 1 inclusive, where *n* is the number of bits that variant uses. So an | |
67 | `i8` can store numbers from -(2<sup>7</sup>) to 2<sup>7</sup> - 1, which equals | |
68 | -128 to 127. Unsigned variants can store numbers from 0 to 2<sup>n</sup> - 1, | |
69 | so a `u8` can store numbers from 0 to 2<sup>8</sup> - 1, which equals 0 to 255. | |
70 | ||
71 | Additionally, the `isize` and `usize` types depend on the kind of computer your | |
72 | program is running on: 64 bits if you’re on a 64-bit architecture and 32 bits | |
73 | if you’re on a 32-bit architecture. | |
74 | ||
75 | You can write integer literals in any of the forms shown in Table 3-2. Note | |
136023e0 XL |
76 | that number literals that can be multiple numeric types allow a type suffix, |
77 | such as `57u8`, to designate the type. Number literals can also use `_` as a | |
78 | visual separator to make the number easier to read, such as `1_000`, which will | |
79 | have the same value as if you had specified `1000`. | |
13cf67c4 XL |
80 | |
81 | <span class="caption">Table 3-2: Integer Literals in Rust</span> | |
82 | ||
83 | | Number literals | Example | | |
84 | |------------------|---------------| | |
85 | | Decimal | `98_222` | | |
86 | | Hex | `0xff` | | |
87 | | Octal | `0o77` | | |
88 | | Binary | `0b1111_0000` | | |
89 | | Byte (`u8` only) | `b'A'` | | |
90 | ||
91 | So how do you know which type of integer to use? If you’re unsure, Rust’s | |
136023e0 XL |
92 | defaults are generally good places to start: integer types default to `i32`. |
93 | The primary situation in which you’d use `isize` or `usize` is when indexing | |
94 | some sort of collection. | |
13cf67c4 | 95 | |
9fa01778 XL |
96 | > ##### Integer Overflow |
97 | > | |
532ac7d7 XL |
98 | > Let’s say you have a variable of type `u8` that can hold values between 0 and 255. |
99 | > If you try to change the variable to a value outside of that range, such | |
100 | > as 256, *integer overflow* will occur. Rust has some interesting rules | |
101 | > involving this behavior. When you’re compiling in debug mode, Rust includes | |
102 | > checks for integer overflow that cause your program to *panic* at runtime if | |
103 | > this behavior occurs. Rust uses the term panicking when a program exits with | |
104 | > an error; we’ll discuss panics in more depth in the [“Unrecoverable Errors | |
dc9dc135 XL |
105 | > with `panic!`”][unrecoverable-errors-with-panic]<!-- ignore --> section in |
106 | > Chapter 9. | |
9fa01778 | 107 | > |
532ac7d7 XL |
108 | > When you’re compiling in release mode with the `--release` flag, Rust does |
109 | > *not* include checks for integer overflow that cause panics. Instead, if | |
110 | > overflow occurs, Rust performs *two’s complement wrapping*. In short, values | |
111 | > greater than the maximum value the type can hold “wrap around” to the minimum | |
112 | > of the values the type can hold. In the case of a `u8`, 256 becomes 0, 257 | |
113 | > becomes 1, and so on. The program won’t panic, but the variable will have a | |
114 | > value that probably isn’t what you were expecting it to have. Relying on | |
fc512014 XL |
115 | > integer overflow’s wrapping behavior is considered an error. |
116 | > | |
117 | > To explicitly handle the possibility of overflow, you can use these families | |
118 | > of methods that the standard library provides on primitive numeric types: | |
119 | > | |
120 | > - Wrap in all modes with the `wrapping_*` methods, such as `wrapping_add` | |
121 | > - Return the `None` value if there is overflow with the `checked_*` methods | |
122 | > - Return the value and a boolean indicating whether there was overflow with | |
123 | > the `overflowing_*` methods | |
124 | > - Saturate at the value's minimum or maximum values with `saturating_*` | |
125 | > methods | |
13cf67c4 XL |
126 | |
127 | #### Floating-Point Types | |
128 | ||
129 | Rust also has two primitive types for *floating-point numbers*, which are | |
130 | numbers with decimal points. Rust’s floating-point types are `f32` and `f64`, | |
131 | which are 32 bits and 64 bits in size, respectively. The default type is `f64` | |
132 | because on modern CPUs it’s roughly the same speed as `f32` but is capable of | |
133 | more precision. | |
134 | ||
135 | Here’s an example that shows floating-point numbers in action: | |
136 | ||
137 | <span class="filename">Filename: src/main.rs</span> | |
138 | ||
139 | ```rust | |
74b04a01 | 140 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-06-floating-point/src/main.rs}} |
13cf67c4 XL |
141 | ``` |
142 | ||
143 | Floating-point numbers are represented according to the IEEE-754 standard. The | |
144 | `f32` type is a single-precision float, and `f64` has double precision. | |
145 | ||
146 | #### Numeric Operations | |
147 | ||
148 | Rust supports the basic mathematical operations you’d expect for all of the | |
149 | number types: addition, subtraction, multiplication, division, and remainder. | |
150 | The following code shows how you’d use each one in a `let` statement: | |
151 | ||
152 | <span class="filename">Filename: src/main.rs</span> | |
153 | ||
154 | ```rust | |
74b04a01 | 155 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-07-numeric-operations/src/main.rs}} |
13cf67c4 XL |
156 | ``` |
157 | ||
158 | Each expression in these statements uses a mathematical operator and evaluates | |
29967ef6 | 159 | to a single value, which is then bound to a variable. [Appendix B][appendix_b]<!-- ignore --> contains a |
13cf67c4 XL |
160 | list of all operators that Rust provides. |
161 | ||
162 | #### The Boolean Type | |
163 | ||
164 | As in most other programming languages, a Boolean type in Rust has two possible | |
9fa01778 XL |
165 | values: `true` and `false`. Booleans are one byte in size. The Boolean type in |
166 | Rust is specified using `bool`. For example: | |
13cf67c4 XL |
167 | |
168 | <span class="filename">Filename: src/main.rs</span> | |
169 | ||
170 | ```rust | |
74b04a01 | 171 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-08-boolean/src/main.rs}} |
13cf67c4 XL |
172 | ``` |
173 | ||
69743fb6 | 174 | The main way to use Boolean values is through conditionals, such as an `if` |
9fa01778 XL |
175 | expression. We’ll cover how `if` expressions work in Rust in the [“Control |
176 | Flow”][control-flow]<!-- ignore --> section. | |
13cf67c4 XL |
177 | |
178 | #### The Character Type | |
179 | ||
180 | So far we’ve worked only with numbers, but Rust supports letters too. Rust’s | |
181 | `char` type is the language’s most primitive alphabetic type, and the following | |
9fa01778 | 182 | code shows one way to use it. (Note that `char` literals are specified with |
13cf67c4 XL |
183 | single quotes, as opposed to string literals, which use double quotes.) |
184 | ||
185 | <span class="filename">Filename: src/main.rs</span> | |
186 | ||
187 | ```rust | |
74b04a01 | 188 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-09-char/src/main.rs}} |
13cf67c4 XL |
189 | ``` |
190 | ||
9fa01778 XL |
191 | Rust’s `char` type is four bytes in size and represents a Unicode Scalar Value, |
192 | which means it can represent a lot more than just ASCII. Accented letters; | |
193 | Chinese, Japanese, and Korean characters; emoji; and zero-width spaces are all | |
194 | valid `char` values in Rust. Unicode Scalar Values range from `U+0000` to | |
195 | `U+D7FF` and `U+E000` to `U+10FFFF` inclusive. However, a “character” isn’t | |
196 | really a concept in Unicode, so your human intuition for what a “character” is | |
197 | may not match up with what a `char` is in Rust. We’ll discuss this topic in | |
198 | detail in [“Storing UTF-8 Encoded Text with Strings”][strings]<!-- ignore --> | |
199 | in Chapter 8. | |
13cf67c4 XL |
200 | |
201 | ### Compound Types | |
202 | ||
203 | *Compound types* can group multiple values into one type. Rust has two | |
204 | primitive compound types: tuples and arrays. | |
205 | ||
206 | #### The Tuple Type | |
207 | ||
e74abb32 XL |
208 | A tuple is a general way of grouping together a number of values with a variety |
209 | of types into one compound type. Tuples have a fixed length: once declared, | |
210 | they cannot grow or shrink in size. | |
13cf67c4 XL |
211 | |
212 | We create a tuple by writing a comma-separated list of values inside | |
213 | parentheses. Each position in the tuple has a type, and the types of the | |
214 | different values in the tuple don’t have to be the same. We’ve added optional | |
215 | type annotations in this example: | |
216 | ||
217 | <span class="filename">Filename: src/main.rs</span> | |
218 | ||
219 | ```rust | |
74b04a01 | 220 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-10-tuples/src/main.rs}} |
13cf67c4 XL |
221 | ``` |
222 | ||
223 | The variable `tup` binds to the entire tuple, because a tuple is considered a | |
224 | single compound element. To get the individual values out of a tuple, we can | |
225 | use pattern matching to destructure a tuple value, like this: | |
226 | ||
227 | <span class="filename">Filename: src/main.rs</span> | |
228 | ||
229 | ```rust | |
74b04a01 | 230 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-11-destructuring-tuples/src/main.rs}} |
13cf67c4 XL |
231 | ``` |
232 | ||
233 | This program first creates a tuple and binds it to the variable `tup`. It then | |
234 | uses a pattern with `let` to take `tup` and turn it into three separate | |
235 | variables, `x`, `y`, and `z`. This is called *destructuring*, because it breaks | |
236 | the single tuple into three parts. Finally, the program prints the value of | |
237 | `y`, which is `6.4`. | |
238 | ||
239 | In addition to destructuring through pattern matching, we can access a tuple | |
240 | element directly by using a period (`.`) followed by the index of the value we | |
241 | want to access. For example: | |
242 | ||
243 | <span class="filename">Filename: src/main.rs</span> | |
244 | ||
245 | ```rust | |
74b04a01 | 246 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-12-tuple-indexing/src/main.rs}} |
13cf67c4 XL |
247 | ``` |
248 | ||
249 | This program creates a tuple, `x`, and then makes new variables for each | |
e74abb32 XL |
250 | element by using their respective indices. As with most programming languages, |
251 | the first index in a tuple is 0. | |
13cf67c4 XL |
252 | |
253 | #### The Array Type | |
254 | ||
255 | Another way to have a collection of multiple values is with an *array*. Unlike | |
256 | a tuple, every element of an array must have the same type. Arrays in Rust are | |
257 | different from arrays in some other languages because arrays in Rust have a | |
258 | fixed length, like tuples. | |
259 | ||
260 | In Rust, the values going into an array are written as a comma-separated list | |
261 | inside square brackets: | |
262 | ||
263 | <span class="filename">Filename: src/main.rs</span> | |
264 | ||
265 | ```rust | |
74b04a01 | 266 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-13-arrays/src/main.rs}} |
13cf67c4 XL |
267 | ``` |
268 | ||
269 | Arrays are useful when you want your data allocated on the stack rather than | |
69743fb6 | 270 | the heap (we will discuss the stack and the heap more in Chapter 4) or when |
13cf67c4 XL |
271 | you want to ensure you always have a fixed number of elements. An array isn’t |
272 | as flexible as the vector type, though. A vector is a similar collection type | |
273 | provided by the standard library that *is* allowed to grow or shrink in size. | |
274 | If you’re unsure whether to use an array or a vector, you should probably use a | |
275 | vector. Chapter 8 discusses vectors in more detail. | |
276 | ||
277 | An example of when you might want to use an array rather than a vector is in a | |
278 | program that needs to know the names of the months of the year. It’s very | |
279 | unlikely that such a program will need to add or remove months, so you can use | |
e74abb32 | 280 | an array because you know it will always contain 12 elements: |
13cf67c4 XL |
281 | |
282 | ```rust | |
283 | let months = ["January", "February", "March", "April", "May", "June", "July", | |
284 | "August", "September", "October", "November", "December"]; | |
285 | ``` | |
286 | ||
532ac7d7 XL |
287 | You would write an array’s type by using square brackets, and within the |
288 | brackets include the type of each element, a semicolon, and then the number of | |
289 | elements in the array, like so: | |
13cf67c4 XL |
290 | |
291 | ```rust | |
292 | let a: [i32; 5] = [1, 2, 3, 4, 5]; | |
293 | ``` | |
294 | ||
9fa01778 | 295 | Here, `i32` is the type of each element. After the semicolon, the number `5` |
e74abb32 | 296 | indicates the array contains five elements. |
9fa01778 | 297 | |
532ac7d7 | 298 | Writing an array’s type this way looks similar to an alternative syntax for |
9fa01778 | 299 | initializing an array: if you want to create an array that contains the same |
532ac7d7 XL |
300 | value for each element, you can specify the initial value, followed by a |
301 | semicolon, and then the length of the array in square brackets, as shown here: | |
9fa01778 XL |
302 | |
303 | ```rust | |
304 | let a = [3; 5]; | |
305 | ``` | |
306 | ||
532ac7d7 | 307 | The array named `a` will contain `5` elements that will all be set to the value |
9fa01778 XL |
308 | `3` initially. This is the same as writing `let a = [3, 3, 3, 3, 3];` but in a |
309 | more concise way. | |
13cf67c4 XL |
310 | |
311 | ##### Accessing Array Elements | |
312 | ||
313 | An array is a single chunk of memory allocated on the stack. You can access | |
314 | elements of an array using indexing, like this: | |
315 | ||
316 | <span class="filename">Filename: src/main.rs</span> | |
317 | ||
318 | ```rust | |
74b04a01 | 319 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-14-array-indexing/src/main.rs}} |
13cf67c4 XL |
320 | ``` |
321 | ||
322 | In this example, the variable named `first` will get the value `1`, because | |
323 | that is the value at index `[0]` in the array. The variable named `second` will | |
324 | get the value `2` from index `[1]` in the array. | |
325 | ||
326 | ##### Invalid Array Element Access | |
327 | ||
328 | What happens if you try to access an element of an array that is past the end | |
5869c6ff XL |
329 | of the array? Say you change the example to the following, which uses code |
330 | similar to the guessing game in Chapter 2 to get an array index from the user: | |
13cf67c4 XL |
331 | |
332 | <span class="filename">Filename: src/main.rs</span> | |
333 | ||
6a06907d | 334 | ```rust,ignore,panics |
74b04a01 | 335 | {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs}} |
13cf67c4 XL |
336 | ``` |
337 | ||
5869c6ff XL |
338 | This code compiles successfully. If you run this code using `cargo run` and |
339 | enter 0, 1, 2, 3, or 4, the program will print out the corresponding value at | |
340 | that index in the array. If you instead enter a number past the end of the | |
341 | array, such as 10, you'll see output like this: | |
342 | ||
343 | <!-- manual-regeneration | |
344 | cd listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access | |
345 | cargo run | |
346 | 10 | |
347 | --> | |
13cf67c4 | 348 | |
f035d41b | 349 | ```console |
5869c6ff XL |
350 | thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:19:19 |
351 | note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace | |
13cf67c4 XL |
352 | ``` |
353 | ||
5869c6ff | 354 | The program resulted in a *runtime* error at the point of using an invalid |
6a06907d XL |
355 | value in the indexing operation. The program exited with an error message and |
356 | didn't execute the final `println!` statement. When you attempt to access an | |
13cf67c4 | 357 | element using indexing, Rust will check that the index you’ve specified is less |
6a06907d XL |
358 | than the array length. If the index is greater than or equal to the length, |
359 | Rust will panic. This check has to happen at runtime, especially in this case, | |
360 | because the compiler can't possibly know what value a user will enter when they | |
361 | run the code later. | |
13cf67c4 XL |
362 | |
363 | This is the first example of Rust’s safety principles in action. In many | |
364 | low-level languages, this kind of check is not done, and when you provide an | |
365 | incorrect index, invalid memory can be accessed. Rust protects you against this | |
366 | kind of error by immediately exiting instead of allowing the memory access and | |
367 | continuing. Chapter 9 discusses more of Rust’s error handling. | |
9fa01778 XL |
368 | |
369 | [comparing-the-guess-to-the-secret-number]: | |
370 | ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number | |
371 | [control-flow]: ch03-05-control-flow.html#control-flow | |
372 | [strings]: ch08-02-strings.html#storing-utf-8-encoded-text-with-strings | |
373 | [unrecoverable-errors-with-panic]: ch09-01-unrecoverable-errors-with-panic.html | |
532ac7d7 | 374 | [wrapping]: ../std/num/struct.Wrapping.html |
29967ef6 | 375 | [appendix_b]: appendix-02-operators.md |