|
|
| (9 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| Go blog post: arrays, slices, and strings: https://blog.golang.org/slices | | Go blog post: arrays, slices, and strings: https://blog.golang.org/slices |
|
| |
|
| =Arrays in Go= | | =Basics= |
|
| |
|
| "Arrays are not often seen in Go programs because the size of an array is part of its type, which limits its expressive power."
| | ==Initialization== |
|
| |
|
| The most common use of arrays are to store slices, which we will see in a moment. | | The most important thing to understand about arrays is that they are different from slices. |
|
| |
|
| ==Array size is a part of the type==
| | If we create the variable like this: |
| | |
| An important characteristic of arrays is that their size is a part of their type.
| |
| | |
| The two variables defined here are of two distinct types:
| |
|
| |
|
| <pre> | | <pre> |
| var buffer [256]byte | | var keys [3]int |
| var buffer2 [512]byte
| |
| </pre> | | </pre> |
|
| |
|
| This is because the size of the array is allocated at initialization time. You can use the square bracket syntax to access elements of an array, <code>buffer[0]</code> through <code>buffer[255]</code>. The program crashes if you access an index outside of its range.
| | it is an array type. That's because we've specified the precise capacity that keys should have. |
| | |
| ==Array slices==
| |
|
| |
|
| The bracket notation with colons can be used to refer to a slice of an array. For example:
| | But if we create the variable like this: |
|
| |
|
| <pre> | | <pre> |
| var buffer [256]byte | | var keys []int |
| ...
| |
| var slice []byte = buffer[100:150]
| |
| </pre> | | </pre> |
|
| |
|
| alternatively,
| | it is a slice type. That's because we did not specify the capacity. |
|
| |
|
| <pre>
| | In both cases, we have not actually initialized the value of either variable. Here's how we create an array: |
| slice := buffer[100:150]
| |
| </pre>
| |
| | |
| Think of a slice variable as a data structure with two elements: a length, and a pointer to an element of the array.
| |
| | |
| We can also take a slice of the slice:
| |
|
| |
|
| <pre> | | <pre> |
| slice2 := slice[5:10]
| | keys := [3]int{10,20,30} |
| </pre> | | </pre> |
|
| |
|
| Here's a shortcut to drop the first and last elements:
| | ==Array size is a part of the type== |
|
| |
|
| <pre>
| | An important characteristic of arrays is that their size is a part of their type. |
| slice3 := slice[1:len(slice)-1]
| |
| </pre>
| |
|
| |
|
| ===References vs Copies===
| | "Arrays are not often seen in Go programs because the size of an array is part of its type, which limits its expressive power." |
|
| |
|
| It is important to distinguish between the slice data structure, which is a small bundle that contains a reference to the underlying array data and a length, and the underlying array data itself.
| | The two variables defined here are of two distinct types: |
| | |
| if we use a slice to modify the underlying array data, those changes will be persistent across functions and scopes. But if we modify the slice variable directly, we are modifying a copy of the slice data structure, and we will discard that copy when we leave that scope.
| |
| | |
| ===Example modifying underlying array data===
| |
| | |
| The following example modifies the underlying array data:
| |
|
| |
|
| <pre> | | <pre> |
| func AddOneToEachElement(slice []byte) {
| | var buffer [256]byte |
| for i := range slice {
| | var buffer2 [512]byte |
| slice[i]++
| |
| }
| |
| }
| |
| | |
| func main() {
| |
| slice := buffer[10:20]
| |
| for i := 0; i < len(slice); i++ {
| |
| slice[i] = byte(i)
| |
| }
| |
| fmt.Println("before", slice)
| |
| AddOneToEachElement(slice)
| |
| fmt.Println("after", slice)
| |
| }
| |
| </pre> | | </pre> |
|
| |
|
| Again, this requires us to think about the array slice as a data structure, which contains a pointer to an array and a length. The bundle, the data structure, is not a pointer itself!
| | This is because the size of the array is allocated at initialization time. You can use the square bracket syntax to access elements of an array, <code>buffer[0]</code> through <code>buffer[255]</code>. The program crashes if you access an index outside of its range. |
|
| |
|
| Even though the slice (also called the "slice header") is passed by value, the header includes a pointer to elements of an array. Thus, both the original and the copy passed to the function refer to the same underlying array (slots in memory).
| | ==Array slices== |
| | |
| ===Example modifying copy of slice===
| |
| | |
| The argument to the SubtractOneFromLength function is a slice, which in this case is a copy of the original slice data structure, containing a reference to the same underlying data.
| |
| | |
| When we modify the slice variable directly, those changes only affect the copy of the data slice, so the original slice is not affected.
| |
| | |
| <pre>
| |
| func SubtractOneFromLength(slice []byte) []byte {
| |
| slice = slice[0 : len(slice)-1]
| |
| return slice
| |
| }
| |
| | |
| func main() {
| |
| fmt.Println("Before: len(slice) =", len(slice))
| |
| newSlice := SubtractOneFromLength(slice)
| |
| fmt.Println("After: len(slice) =", len(slice))
| |
| fmt.Println("After: len(newSlice) =", len(newSlice))
| |
| }
| |
| </pre>
| |
| | |
| | |
| ===Array Slice Capacity===
| |
| | |
| The capacity of an array is fixed; to make a new array with a new capacity, use the make() function.
| |
| | |
| The make function allocates space in memory for an array slice with a specified capacity.
| |
| | |
| The make function takes three arguments: the type of the slice, its initial length, and its capacity, which is the length of the array that make allocates to hold the slice data.
| |
| | |
| <pre>
| |
| // Make an array slice with a length of 100 and room for 5 more
| |
| slice := make([]int, 100, 15)
| |
| </pre>
| |
| | |
| To double the array slice capacity:
| |
| | |
| <pre>
| |
| // Original slice:
| |
| slice := make([]int, 10, 15)
| |
| fmt.Printf("len: %d, cap: %d\n", len(slice), cap(slice))
| |
| | |
| // New slice (double the capacity):
| |
| newSlice := make([]int, len(slice), 2*cap(slice))
| |
| for i := range slice {
| |
| newSlice[i] = slice[i]
| |
| }
| |
| | |
| // Replace old with new
| |
| slice = newSlice
| |
| fmt.Printf("len: %d, cap: %d\n", len(slice), cap(slice))
| |
| </pre>
| |
| | |
| The above code is functional but awkward; Go provides a copy function to copy an old array into a new array, to accomplish the above in fewer lines.
| |
| | |
| <pre>
| |
| newSlice := make([]int, len(slice), 2*cap(slice))
| |
| copy(newSlice, slice)
| |
| </pre>
| |
| | |
| Note that copy is smart - it will copy as much as it can, but will respect the lengths of both array slices rfg.
| |
| | |
| ===Array Slice Insertion===
| |
| | |
| The Go blog gets lost on a (rather stupid and uninformative) topic, which is, array slices.
| |
| | |
| To insert an element into a slice of an array, we can do the following (NOTE: This is NOT the same as inserting an element into an array):
| |
| | |
| * Extend the slice window by 1
| |
| * Shift the upper part of the slice's underlying array data up by 1, using the copy function
| |
| ** Copying FROM the variable slice, starting at index and running to the end
| |
| ** Copying TO the variable slice, starting at index + 1 and running to the end
| |
| * Return the new slice
| |
| | |
| This operation WILL NOT affect the underlying data.
| |
| | |
| Here is the Insert function, plus a main method that calls it:
| |
| | |
| <pre>
| |
| // Insert inserts the value into the slice at the specified index,
| |
| // which must be in range.
| |
| // The slice must have room for the new element.
| |
| func Insert(slice []int, index, value int) []int {
| |
| | |
| // Grow the slice by one element.
| |
| slice = slice[0 : len(slice)+1]
| |
| | |
| // Use copy to move the upper part of the slice out of the way and open a hole.
| |
| copy(slice[index+1:], slice[index:])
| |
| | |
| // Store the new value.
| |
| slice[index] = value
| |
| | |
| // Return the result.
| |
| return slice
| |
| }
| |
| </pre>
| |
|
| |
|
| Aside from the stupidity of the example (not making clear why you would want to insert something into a slice of an array but not the array itself; not making clear the underlying data or the memory/reference model in Go).
| | See [[Go/Slices]] |
|
| |
|
| Basically this whole blog post is a hot mess.
| | ==Comparison== |
|
| |
|
| The confusion here is, the text seems to contradict the behavior of this function.
| | Let's cover how to compare arrays. |
|
| |
|
| * The text describing this example insists we are passing a copy of the slice, but that copy should refer to the same data underneath.
| | Array values are comparable if values of the array element type are comparable. |
| * However, when we expand the length of the slice, and shift everything over, and insert a value, this doesn't affect the data underneath.
| |
|
| |
|
| The answer: we aren't creating a slice by saying <code>slice = orig[5:10]</code>, we are creating a slice by saying <code>slice = make([]int, 4, 8)</code> and then <code>copy(slice,orig)</code>.
| | Two array values are equal if their corresponding elements are equal. |
|
| |
|
| When we call make, we're basically allocating an underlying array for a slice.
| | However, note that you cannot compare slices: https://play.golang.org/p/Kk8osjPm8n |
|
| |
|
| [https://stackoverflow.com/questions/9320862/why-would-i-make-or-new Related question on Stack Overflow]
| | Likewise: https://play.golang.org/p/kCVoPekPudc |
|
| |
|
| =Flags= | | =Flags= |
|
| |
|
| {{GoFlag}} | | {{GoFlag}} |
Go blog post: arrays, slices, and strings: https://blog.golang.org/slices
Basics
Initialization
The most important thing to understand about arrays is that they are different from slices.
If we create the variable like this:
var keys [3]int
it is an array type. That's because we've specified the precise capacity that keys should have.
But if we create the variable like this:
var keys []int
it is a slice type. That's because we did not specify the capacity.
In both cases, we have not actually initialized the value of either variable. Here's how we create an array:
keys := [3]int{10,20,30}
Array size is a part of the type
An important characteristic of arrays is that their size is a part of their type.
"Arrays are not often seen in Go programs because the size of an array is part of its type, which limits its expressive power."
The two variables defined here are of two distinct types:
var buffer [256]byte
var buffer2 [512]byte
This is because the size of the array is allocated at initialization time. You can use the square bracket syntax to access elements of an array, buffer[0] through buffer[255]. The program crashes if you access an index outside of its range.
Array slices
See Go/Slices
Comparison
Let's cover how to compare arrays.
Array values are comparable if values of the array element type are comparable.
Two array values are equal if their corresponding elements are equal.
However, note that you cannot compare slices: https://play.golang.org/p/Kk8osjPm8n
Likewise: https://play.golang.org/p/kCVoPekPudc
Flags