# arrays Arrays are useful when planning the detailed layout of memory and sometimes can help avoid allocation, but primarily they are a building block for slices, the subject of the next section. To lay the foundation for that topic, here are a few words about arrays. There are major differences between the ways arrays work in Go and C. In Go, * Arrays are values. Assigning one array to another copies all the elements. * In particular, if you pass an array to a function, it will receive a copy of the array, not a pointer to it. * The size of an array is part of its type. The types `[10]int` and `[20]int` are distinct. The value property can be useful but also expensive; if you want C-like behavior and efficiency, you can pass a pointer to the array. ```go func Sum(a *[3]float64) (sum float64) { for _, v := range *a { sum += v } return } array := [...]float64{7.0, 8.5, 9.1} x := Sum(&array) // Note the explicit address-of operator ``` But even this style isn't idiomatic Go. Use slices instead. # slices Slices wrap arrays to give a more general, powerful, and convenient interface to sequences of data. Except for items with explicit dimension such as transformation matrices, most array programming in Go is done with slices rather than simple arrays. Slices hold references to an underlying array, and if you assign one slice to another, both refer to the same array. If a function takes a slice argument, changes it makes to the elements of the slice will be visible to the caller, analogous to passing a pointer to the underlying array. A `Read` function can therefore accept a slice argument rather than a pointer and a count; the length within the slice sets an upper limit of how much data to read. Here is the signature of the `Read` method of the `File` type in package `os`: ```go func (f *File) Read(buf []byte) (n int, err error) ``` The method returns the number of bytes read and an error value, if any. To read into the first 32 bytes of a larger buffer `buf`, slice (here used as a verb) the buffer. ```go n, err := f.Read(buf[0:32]) ``` Such slicing is common and efficient. In fact, leaving efficiency aside for the moment, the following snippet would also read the first 32 bytes of the buffer. ```go var n int var err error for i := 0; i < 32; i++ { nbytes, e := f.Read(buf[i:i+1]) // Read one byte. n += nbytes if nbytes == 0 || e != nil { err = e break } } ``` The length of a slice may be changed as long as it still fits within the limits of the underlying array; just assign it to a slice of itself. The capacity of a slice, accessible by the built-in function `cap`, reports the maximum length the slice may assume. Here is a function to append data to a slice. If the data exceeds the capacity, the slice is reallocated. The resulting slice is returned. The function uses the fact that `len` and `cap` are legal when applied to the `nil` slice, and return 0. ```go func Append(slice, data []byte) []byte { l := len(slice) if l + len(data) > cap(slice) { // reallocate // Allocate double what's needed, for future growth. newSlice := make([]byte, (l+len(data))*2) // The copy function is predeclared and works for any slice type. copy(newSlice, slice) slice = newSlice } slice = slice[0:l+len(data)] copy(slice[l:], data) return slice } ``` We must return the slice afterwards because, although Append can modify the elements of slice, the slice itself (the run-time data structure holding the pointer, length, and capacity) is passed by value. The idea of appending to a slice is so useful it's captured by the append built-in function. To understand that function's design, though, we need a little more information, so we'll return to it later. # two-dimensional slices Go's arrays and slices are one-dimensional. To create the equivalent of a 2D array or slice, it is necessary to define an array-of-arrays or slice-of-slices, like this: ```go type Transform [3][3]float64 // A 3x3 array, really an array of arrays. type LinesOfText [][]byte // A slice of byte slices. ``` Because slices are variable-length, it is possible to have each inner slice be a different length. That can be a common situation, as in our `LinesOfText` example: each line has an independent length. ```go text := LinesOfText { []byte("Now is the time"), []byte("for all good gophers"), []byte("to bring some fun to the party."), } ``` Sometimes it's necessary to allocate a 2D slice, a situation that can arise when processing scan lines of pixels, for instance. There are two ways to achieve this. One is to allocate each slice independently; the other is to allocate a single array and point the individual slices into it. Which to use depends on your application. If the slices might grow or shrink, they should be allocated independently to avoid overwriting the next line; if not, it can be more efficient to construct the object with a single allocation. For reference, here are sketches of the two methods. First, a line at a time: ```go // Allocate the top-level slice. picture := make([][]uint8, YSize) // One row per unit of y. // Loop over the rows, allocating the slice for each row. for i := range picture { picture[i] = make([]uint8, XSize) } ``` And now as one allocation, sliced into lines: ```go // Allocate the top-level slice, the same as before. picture := make([][]uint8, YSize) // One row per unit of y. // Allocate one large slice to hold all the pixels. pixels := make([]uint8, XSize*YSize) // Has type []uint8 even though picture is [][]uint8. // Loop over the rows, slicing each row from the front of the remaining pixels slice. for i := range picture { picture[i], pixels = pixels[:XSize], pixels[XSize:] } ``` # maps Maps are a convenient and powerful built-in data structure that associate values of one type (the key) with values of another type (the element or value). The key can be of any type for which the equality operator is defined, such as integers, floating point and complex numbers, strings, pointers, interfaces (as long as the dynamic type supports equality), structs and arrays. Slices cannot be used as map keys, because equality is not defined on them. Like slices, maps hold references to an underlying data structure. If you pass a map to a function that changes the contents of the map, the changes will be visible in the caller. Maps can be constructed using the usual composite literal syntax with colon-separated key-value pairs, so it's easy to build them during initialization. ```go var timeZone = map[string]int{ "UTC": 0*60*60, "EST": -5*60*60, "CST": -6*60*60, "MST": -7*60*60, "PST": -8*60*60, } ``` Assigning and fetching map values looks syntactically just like doing the same for arrays and slices except that the index doesn't need to be an integer. ```go offset := timeZone["EST"] ``` An attempt to fetch a map value with a key that is not present in the map will return the zero value for the type of the entries in the map. For instance, if the map contains integers, looking up a non-existent key will return 0. A set can be implemented as a map with value type bool. Set the map entry to true to put the value in the set, and then test it by simple indexing. ```go attended := map[string]bool{ "Ann": true, "Joe": true, ... } ``` ```go if attended[person] { // will be false if person is not in the map fmt.Println(person, "was at the meeting") } ``` Sometimes you need to distinguish a missing entry from a zero value. Is there an entry for "UTC" or is that 0 because it's not in the map at all? You can discriminate with a form of multiple assignment. ```go var seconds int var ok bool seconds, ok = timeZone[tz] ``` For obvious reasons this is called the “comma ok” idiom. In this example, if tz is present, seconds will be set appropriately and ok will be true; if not, seconds will be set to zero and ok will be false. Here's a function that puts it together with a nice error report: ```go func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 } ``` To test for presence in the map without worrying about the actual value, you can use the blank identifier (_) in place of the usual variable for the value. ```go _, present := timeZone[tz] ``` To delete a map entry, use the delete built-in function, whose arguments are the map and the key to be deleted. It's safe to do this even if the key is already absent from the map. ```go delete(timeZone, "PDT") // Now on Standard Time ```