]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch08-01-vectors.md
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / src / doc / book / src / ch08-01-vectors.md
1 ## Storing Lists of Values with Vectors
2
3 The first collection type we’ll look at is `Vec<T>`, also known as a *vector*.
4 Vectors allow you to store more than one value in a single data structure that
5 puts all the values next to each other in memory. Vectors can only store values
6 of the same type. They are useful when you have a list of items, such as the
7 lines of text in a file or the prices of items in a shopping cart.
8
9 ### Creating a New Vector
10
11 To create a new, empty vector, we can call the `Vec::new` function, as shown in
12 Listing 8-1.
13
14 ```rust
15 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-01/src/main.rs:here}}
16 ```
17
18 <span class="caption">Listing 8-1: Creating a new, empty vector to hold values
19 of type `i32`</span>
20
21 Note that we added a type annotation here. Because we aren’t inserting any
22 values into this vector, Rust doesn’t know what kind of elements we intend to
23 store. This is an important point. Vectors are implemented using generics;
24 we’ll cover how to use generics with your own types in Chapter 10. For now,
25 know that the `Vec<T>` type provided by the standard library can hold any type,
26 and when a specific vector holds a specific type, the type is specified within
27 angle brackets. In Listing 8-1, we’ve told Rust that the `Vec<T>` in `v` will
28 hold elements of the `i32` type.
29
30 In more realistic code, Rust can often infer the type of value you want to
31 store once you insert values, so you rarely need to do this type annotation.
32 It’s more common to create a `Vec<T>` that has initial values, and Rust
33 provides the `vec!` macro for convenience. The macro will create a new vector
34 that holds the values you give it. Listing 8-2 creates a new `Vec<i32>` that
35 holds the values `1`, `2`, and `3`. The integer type is `i32` because that’s
36 the default integer type, as we discussed in the [“Data Types”][data-types]<!--
37 ignore --> section of Chapter 3.
38
39 ```rust
40 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-02/src/main.rs:here}}
41 ```
42
43 <span class="caption">Listing 8-2: Creating a new vector containing
44 values</span>
45
46 Because we’ve given initial `i32` values, Rust can infer that the type of `v`
47 is `Vec<i32>`, and the type annotation isn’t necessary. Next, we’ll look at how
48 to modify a vector.
49
50 ### Updating a Vector
51
52 To create a vector and then add elements to it, we can use the `push` method,
53 as shown in Listing 8-3.
54
55 ```rust
56 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-03/src/main.rs:here}}
57 ```
58
59 <span class="caption">Listing 8-3: Using the `push` method to add values to a
60 vector</span>
61
62 As with any variable, if we want to be able to change its value, we need to
63 make it mutable using the `mut` keyword, as discussed in Chapter 3. The numbers
64 we place inside are all of type `i32`, and Rust infers this from the data, so
65 we don’t need the `Vec<i32>` annotation.
66
67 ### Dropping a Vector Drops Its Elements
68
69 Like any other `struct`, a vector is freed when it goes out of scope, as
70 annotated in Listing 8-4.
71
72 ```rust
73 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}}
74 ```
75
76 <span class="caption">Listing 8-4: Showing where the vector and its elements
77 are dropped</span>
78
79 When the vector gets dropped, all of its contents are also dropped, meaning
80 those integers it holds will be cleaned up. This may seem like a
81 straightforward point but can get a bit more complicated when you start to
82 introduce references to the elements of the vector. Let’s tackle that next!
83
84 ### Reading Elements of Vectors
85
86 Now that you know how to create, update, and destroy vectors, knowing how to
87 read their contents is a good next step. There are two ways to reference a
88 value stored in a vector. In the examples, we’ve annotated the types of the
89 values that are returned from these functions for extra clarity.
90
91 Listing 8-5 shows both methods of accessing a value in a vector, either with
92 indexing syntax or the `get` method.
93
94 ```rust
95 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-05/src/main.rs:here}}
96 ```
97
98 <span class="caption">Listing 8-5: Using indexing syntax or the `get` method to
99 access an item in a vector</span>
100
101 Note two details here. First, we use the index value of `2` to get the third
102 element: vectors are indexed by number, starting at zero. Second, the two ways
103 to get the third element are by using `&` and `[]`, which gives us a reference,
104 or by using the `get` method with the index passed as an argument, which gives
105 us an `Option<&T>`.
106
107 Rust has two ways to reference an element so you can choose how the program
108 behaves when you try to use an index value that the vector doesn’t have an
109 element for. As an example, let’s see what a program will do if it has a vector
110 that holds five elements and then tries to access an element at index 100, as
111 shown in Listing 8-6.
112
113 ```rust,should_panic,panics
114 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}}
115 ```
116
117 <span class="caption">Listing 8-6: Attempting to access the element at index
118 100 in a vector containing five elements</span>
119
120 When we run this code, the first `[]` method will cause the program to panic
121 because it references a nonexistent element. This method is best used when you
122 want your program to crash if there’s an attempt to access an element past the
123 end of the vector.
124
125 When the `get` method is passed an index that is outside the vector, it returns
126 `None` without panicking. You would use this method if accessing an element
127 beyond the range of the vector happens occasionally under normal circumstances.
128 Your code will then have logic to handle having either `Some(&element)` or
129 `None`, as discussed in Chapter 6. For example, the index could be coming from
130 a person entering a number. If they accidentally enter a number that’s too
131 large and the program gets a `None` value, you could tell the user how many
132 items are in the current vector and give them another chance to enter a valid
133 value. That would be more user-friendly than crashing the program due to a typo!
134
135 When the program has a valid reference, the borrow checker enforces the
136 ownership and borrowing rules (covered in Chapter 4) to ensure this reference
137 and any other references to the contents of the vector remain valid. Recall the
138 rule that states you can’t have mutable and immutable references in the same
139 scope. That rule applies in Listing 8-7, where we hold an immutable reference to
140 the first element in a vector and try to add an element to the end, which won’t
141 work if we also try to refer to that element later in the function:
142
143 ```rust,ignore,does_not_compile
144 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}}
145 ```
146
147 <span class="caption">Listing 8-7: Attempting to add an element to a vector
148 while holding a reference to an item</span>
149
150 Compiling this code will result in this error:
151
152 ```console
153 {{#include ../listings/ch08-common-collections/listing-08-07/output.txt}}
154 ```
155
156 The code in Listing 8-7 might look like it should work: why should a reference
157 to the first element care about what changes at the end of the vector? This
158 error is due to the way vectors work: adding a new element onto the end of the
159 vector might require allocating new memory and copying the old elements to the
160 new space, if there isn’t enough room to put all the elements next to each
161 other where the vector currently is. In that case, the reference to the first
162 element would be pointing to deallocated memory. The borrowing rules prevent
163 programs from ending up in that situation.
164
165 > Note: For more on the implementation details of the `Vec<T>` type, see [“The
166 > Rustonomicon”][nomicon].
167
168 ### Iterating over the Values in a Vector
169
170 If we want to access each element in a vector in turn, we can iterate through
171 all of the elements rather than use indices to access one at a time. Listing
172 8-8 shows how to use a `for` loop to get immutable references to each element
173 in a vector of `i32` values and print them.
174
175 ```rust
176 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-08/src/main.rs:here}}
177 ```
178
179 <span class="caption">Listing 8-8: Printing each element in a vector by
180 iterating over the elements using a `for` loop</span>
181
182 We can also iterate over mutable references to each element in a mutable vector
183 in order to make changes to all the elements. The `for` loop in Listing 8-9
184 will add `50` to each element.
185
186 ```rust
187 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}}
188 ```
189
190 <span class="caption">Listing 8-9: Iterating over mutable references to
191 elements in a vector</span>
192
193 To change the value that the mutable reference refers to, we have to use the
194 dereference operator (`*`) to get to the value in `i` before we can use the
195 `+=` operator. We’ll talk more about the dereference operator in the
196 [“Following the Pointer to the Value with the Dereference Operator”][deref]
197 section of Chapter 15.
198
199 ### Using an Enum to Store Multiple Types
200
201 At the beginning of this chapter, we said that vectors can only store values
202 that are the same type. This can be inconvenient; there are definitely use
203 cases for needing to store a list of items of different types. Fortunately, the
204 variants of an enum are defined under the same enum type, so when we need to
205 store elements of a different type in a vector, we can define and use an enum!
206
207 For example, say we want to get values from a row in a spreadsheet in which
208 some of the columns in the row contain integers, some floating-point numbers,
209 and some strings. We can define an enum whose variants will hold the different
210 value types, and then all the enum variants will be considered the same type:
211 that of the enum. Then we can create a vector that holds that enum and so,
212 ultimately, holds different types. We’ve demonstrated this in Listing 8-10.
213
214 ```rust
215 {{#rustdoc_include ../listings/ch08-common-collections/listing-08-10/src/main.rs:here}}
216 ```
217
218 <span class="caption">Listing 8-10: Defining an `enum` to store values of
219 different types in one vector</span>
220
221 Rust needs to know what types will be in the vector at compile time so it knows
222 exactly how much memory on the heap will be needed to store each element. A
223 secondary advantage is that we can be explicit about what types are allowed in
224 this vector. If Rust allowed a vector to hold any type, there would be a chance
225 that one or more of the types would cause errors with the operations performed
226 on the elements of the vector. Using an enum plus a `match` expression means
227 that Rust will ensure at compile time that every possible case is handled, as
228 discussed in Chapter 6.
229
230 When you’re writing a program, if you don’t know the exhaustive set of types
231 the program will get at runtime to store in a vector, the enum technique won’t
232 work. Instead, you can use a trait object, which we’ll cover in Chapter 17.
233
234 Now that we’ve discussed some of the most common ways to use vectors, be sure
235 to review the API documentation for all the many useful methods defined on
236 `Vec<T>` by the standard library. For example, in addition to `push`, a `pop`
237 method removes and returns the last element. Let’s move on to the next
238 collection type: `String`!
239
240 [data-types]: ch03-02-data-types.html#data-types
241 [nomicon]: ../nomicon/vec.html
242 [deref]: ch15-02-deref.html#following-the-pointer-to-the-value-with-the-dereference-operator