Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1439)

Side by Side Diff: doc/articles/slices_usage_and_internals.tmpl

Issue 5516046: code review 5516046: doc: add Slices: usage and internals article (Closed)
Patch Set: diff -r 6d9aff5b1419 https://go.googlecode.com/hg Created 13 years, 2 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « doc/articles/slices_usage_and_internals.html ('k') | doc/progs/run » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 <!-- Slices: usage and internals -->
2 {{donotedit}}
3
4 <p>
5 Go's slice type provides a convenient and efficient means of working with
6 sequences of typed data. Slices are analogous to arrays in other languages, but
7 have some unusual properties. This article will look at what slices are and how
8 they are used.
9 </p>
10
11 <p>
12 <b>Arrays</b>
13 </p>
14
15 <p>
16 The slice type is an abstraction built on top of Go's array type, and so to
17 understand slices we must first understand arrays.
18 </p>
19
20 <p>
21 An array type definition specifies a length and an element type. For example,
22 the type <code>[4]int</code> represents an array of four integers. An array's
23 size is fixed; its length is part of its type (<code>[4]int</code> and
24 <code>[5]int</code> are distinct, incompatible types). Arrays can be indexed in
25 the usual way, so the expression <code>s[n]</code> accesses the <i>n</i>th
26 element:
27 </p>
28
29 <pre>
30 var a [4]int
31 a[0] = 1
32 i := a[0]
33 // i == 1
34 </pre>
35
36 <p>
37 Arrays do not need to be initialized explicitly; the zero value of an array is
38 a ready-to-use array whose elements are themselves zeroed:
39 </p>
40
41 <pre>
42 // a[2] == 0, the zero value of the int type
43 </pre>
44
45 <p>
46 The in-memory representation of <code>[4]int</code> is just four integer values laid out sequentially:
47 </p>
48
49 <p>
50 <img src="slice-array.png">
51 </p>
52
53 <p>
54 Go's arrays are values. An array variable denotes the entire array; it is not a
55 pointer to the first array element (as would be the case in C). This means
56 that when you assign or pass around an array value you will make a copy of its
57 contents. (To avoid the copy you could pass a <i>pointer</i> to the array, but
58 then that's a pointer to an array, not an array.) One way to think about arrays
59 is as a sort of struct but with indexed rather than named fields: a fixed-size
60 composite value.
61 </p>
62
63 <p>
64 An array literal can be specified like so:
65 </p>
66
67 <pre>
68 b := [2]string{"Penn", "Teller"}
69 </pre>
70
71 <p>
72 Or, you can have the compiler count the array elements for you:
73 </p>
74
75 <pre>
76 b := [...]string{"Penn", "Teller"}
77 </pre>
78
79 <p>
80 In both cases, the type of <code>b</code> is <code>[2]string</code>.
81 </p>
82
83 <p>
84 <b>Slices</b>
85 </p>
86
87 <p>
88 Arrays have their place, but they're a bit inflexible, so you don't see them
89 too often in Go code. Slices, though, are everywhere. They build on arrays to
90 provide great power and convenience.
91 </p>
92
93 <p>
94 The type specification for a slice is <code>[]T</code>, where <code>T</code> is
95 the type of the elements of the slice. Unlike an array type, a slice type has
96 no specified length.
97 </p>
98
99 <p>
100 A slice literal is declared just like an array literal, except you leave out
101 the element count:
102 </p>
103
104 <pre>
105 letters := []string{"a", "b", "c", "d"}
106 </pre>
107
108 <p>
109 A slice can be created with the built-in function called <code>make</code>,
110 which has the signature,
111 </p>
112
113 <pre>
114 func make([]T, len, cap) []T
115 </pre>
116
117 <p>
118 where T stands for the element type of the slice to be created. The
119 <code>make</code> function takes a type, a length, and an optional capacity.
120 When called, <code>make</code> allocates an array and returns a slice that
121 refers to that array.
122 </p>
123
124 <pre>
125 var s []byte
126 s = make([]byte, 5, 5)
127 // s == []byte{0, 0, 0, 0, 0}
128 </pre>
129
130 <p>
131 When the capacity argument is omitted, it defaults to the specified length.
132 Here's a more succinct version of the same code:
133 </p>
134
135 <pre>
136 s := make([]byte, 5)
137 </pre>
138
139 <p>
140 The length and capacity of a slice can be inspected using the built-in
141 <code>len</code> and <code>cap</code> functions.
142 </p>
143
144 <pre>
145 len(s) == 5
146 cap(s) == 5
147 </pre>
148
149 <p>
150 The next two sections discuss the relationship between length and capacity.
151 </p>
152
153 <p>
154 The zero value of a slice is <code>nil</code>. The <code>len</code> and
155 <code>cap</code> functions will both return 0 for a nil slice.
156 </p>
157
158 <p>
159 A slice can also be formed by "slicing" an existing slice or array. Slicing is
160 done by specifying a half-open range with two indices separated by a colon. For
161 example, the expression <code>b[1:4]</code> creates a slice including elements
162 1 through 3 of <code>b</code> (the indices of the resulting slice will be 0
163 through 2).
164 </p>
165
166 <pre>
167 b := []byte{'g', 'o', 'l', 'a', 'n', 'g'}
168 // b[1:4] == []byte{'o', 'l', 'a'}, sharing the same storage as b
169 </pre>
170
171 <p>
172 The start and end indices of a slice expression are optional; they default to ze ro and the slice's length respectively:
173 </p>
174
175 <pre>
176 // b[:2] == []byte{'g', 'o'}
177 // b[2:] == []byte{'l', 'a', 'n', 'g'}
178 // b[:] == b
179 </pre>
180
181 <p>
182 This is also the syntax to create a slice given an array:
183 </p>
184
185 <pre>
186 x := [3]string{"Лайка", "Белка", "Стрелка"}
187 s := x[:] // a slice referencing the storage of x
188 </pre>
189
190 <p>
191 <b>Slice internals</b>
192 </p>
193
194 <p>
195 A slice is a descriptor of an array segment. It consists of a pointer to the
196 array, the length of the segment, and its capacity (the maximum length of the
197 segment).
198 </p>
199
200 <p>
201 <img src="slice-struct.png">
202 </p>
203
204 <p>
205 Our variable <code>s</code>, created earlier by <code>make([]byte, 5)</code>,
206 is structured like this:
207 </p>
208
209 <p>
210 <img src="slice-1.png">
211 </p>
212
213 <p>
214 The length is the number of elements referred to by the slice. The capacity is
215 the number of elements in the underlying array (beginning at the element
216 referred to by the slice pointer). The distinction between length and capacity
217 will be made clear as we walk through the next few examples.
218 </p>
219
220 <p>
221 As we slice <code>s</code>, observe the changes in the slice data structure and
222 their relation to the underlying array:
223 </p>
224
225 <pre>
226 s = s[2:4]
227 </pre>
228
229 <p>
230 <img src="slice-2.png">
231 </p>
232
233 <p>
234 Slicing does not copy the slice's data. It creates a new slice value that
235 points to the original array. This makes slice operations as efficient as
236 manipulating array indices. Therefore, modifying the <i>elements</i> (not the
237 slice itself) of a re-slice modifies the elements of the original slice:
238 </p>
239
240 <pre>
241 d := []byte{'r', 'o', 'a', 'd'}
242 e := d[2:]·
243 // e == []byte{'a', 'd'}
244 e[1] == 'm'
245 // e == []byte{'a', 'm'}
246 // d == []byte{'r', 'o', 'a', 'm'}
247 </pre>
248
249 <p>
250 Earlier we sliced <code>s</code> to a length shorter than its capacity. We can
251 grow s to its capacity by slicing it again:
252 </p>
253
254 <pre>
255 s = s[:cap(s)]
256 </pre>
257
258 <p>
259 <img src="slice-3.png">
260 </p>
261
262 <p>
263 A slice cannot be grown beyond its capacity. Attempting to do so will cause a
264 runtime panic, just as when indexing outside the bounds of a slice or array.
265 Similarly, slices cannot be re-sliced below zero to access earlier elements in
266 the array.
267 </p>
268
269 <p>
270 <b>Growing slices (the copy and append functions)</b>
271 </p>
272
273 <p>
274 To increase the capacity of a slice one must create a new, larger slice and
275 copy the contents of the original slice into it. This technique is how dynamic
276 array implementations from other languages work behind the scenes. The next
277 example doubles the capacity of <code>s</code> by making a new slice,
278 <code>t</code>, copying the contents of <code>s</code> into <code>t</code>, and
279 then assigning the slice value <code>t</code> to <code>s</code>:
280 </p>
281
282 <pre>
283 t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
284 for i := range s {
285 t[i] = s[i]
286 }
287 s = t
288 </pre>
289
290 <p>
291 The looping piece of this common operation is made easier by the built-in copy
292 function. As the name suggests, copy copies data from a source slice to a
293 destination slice. It returns the number of elements copied.
294 </p>
295
296 <pre>
297 func copy(dst, src []T) int
298 </pre>
299
300 <p>
301 The <code>copy</code> function supports copying between slices of different
302 lengths (it will copy only up to the smaller number of elements). In addition,
303 <code>copy</code> can handle source and destination slices that share the same
304 underlying array, handling overlapping slices correctly.
305 </p>
306
307 <p>
308 Using <code>copy</code>, we can simplify the code snippet above:
309 </p>
310
311 <pre>
312 t := make([]byte, len(s), (cap(s)+1)*2)
313 copy(t, s)
314 s = t
315 </pre>
316
317 <p>
318 A common operation is to append data to the end of a slice. This function
319 appends byte elements to a slice of bytes, growing the slice if necessary, and
320 returns the updated slice value:
321 </p>
322
323 {{code "progs/slices.go" `/AppendByte/` `/STOP/`}}
324
325 <p>
326 One could use <code>AppendByte</code> like this:
327 </p>
328
329 <pre>
330 p := []byte{2, 3, 5}
331 p = AppendByte(p, 7, 11, 13)
332 // p == []byte{2, 3, 5, 7, 11, 13}
333 </pre>
334
335 <p>
336 Functions like <code>AppendByte</code> are useful because they offer complete
337 control over the way the slice is grown. Depending on the characteristics of
338 the program, it may be desirable to allocate in smaller or larger chunks, or to
339 put a ceiling on the size of a reallocation.
340 </p>
341
342 <p>
343 But most programs don't need complete control, so Go provides a built-in
344 <code>append</code> function that's good for most purposes; it has the
345 signature
346 </p>
347
348 <pre>
349 func append(s []T, x ...T) []T·
350 </pre>
351
352 <p>
353 The <code>append</code> function appends the elements <code>x</code> to the end
354 of the slice <code>s</code>, and grows the slice if a greater capacity is
355 needed.
356 </p>
357
358 <pre>
359 a := make([]int, 1)
360 // a == []int{0}
361 a = append(a, 1, 2, 3)
362 // a == []int{0, 1, 2, 3}
363 </pre>
364
365 <p>
366 To append one slice to another, use <code>...</code> to expand the second
367 argument to a list of arguments.
368 </p>
369
370 <pre>
371 a := []string{"John", "Paul"}
372 b := []string{"George", "Ringo", "Pete"}
373 a = append(a, b...) // equivalent to "append(a, b[0], b[1], b[2])"
374 // a == []string{"John", "Paul", "George", "Ringo", "Pete"}
375 </pre>
376
377 <p>
378 Since the zero value of a slice (<code>nil</code>) acts like a zero-length
379 slice, you can declare a slice variable and then append to it in a loop:
380 </p>
381
382 {{code "progs/slices.go" `/Filter/` `/STOP/`}}
383
384 <p>
385 <b>A possible "gotcha"</b>
386 </p>
387
388 <p>
389 As mentioned earlier, re-slicing a slice doesn't make a copy of the underlying
390 array. The full array will be kept in memory until it is no longer referenced.
391 Occasionally this can cause the program to hold all the data in memory when
392 only a small piece of it is needed.
393 </p>
394
395 <p>
396 For example, this <code>FindDigits</code> function loads a file into memory and
397 searches it for the first group of consecutive numeric digits, returning them
398 as a new slice.
399 </p>
400
401 {{code "progs/slices.go" `/digit/` `/STOP/`}}
402
403 <p>
404 This code behaves as advertised, but the returned <code>[]byte</code> points
405 into an array containing the entire file. Since the slice references the
406 original array, as long as the slice is kept around the garbage collector can't
407 release the array; the few useful bytes of the file keep the entire contents in
408 memory.
409 </p>
410
411 <p>
412 To fix this problem one can copy the interesting data to a new slice before
413 returning it:
414 </p>
415
416 {{code "progs/slices.go" `/CopyDigits/` `/STOP/`}}
417
418 <p>
419 A more concise version of this function could be constructed by using
420 <code>append</code>. This is left as an exercise for the reader.
421 </p>
422
423 <p>
424 <b>Further Reading</b>
425 </p>
426
427 <p>
428 <a href="/doc/effective_go.html">Effective Go</a> contains an
429 in-depth treatment of <a href="/doc/effective_go.html#slices">slices</a>
430 and <a href="/doc/effective_go.html#arrays">arrays</a>,·
431 and the Go <a href="/doc/go_spec.html">language specification</a>
432 defines <a href="/doc/go_spec.html#Slice_types">slices</a> and their
433 <a href="/doc/go_spec.html#Length_and_capacity">associated</a>
434 <a href="/doc/go_spec.html#Making_slices_maps_and_channels">helper</a>
435 <a href="/doc/go_spec.html#Appending_and_copying_slices">functions</a>.
436 </p>
OLDNEW
« no previous file with comments | « doc/articles/slices_usage_and_internals.html ('k') | doc/progs/run » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b