Slice
Slices use arrays as the underlying data type. The main advantage is that slices can be resized, unlike arrays. Think of slices as a viewing window in to an underlying array. The capacity refers to the size of the underlying array, and the maximum possible length of a slice. The length of a slice refers to its current length which can be resized.
Slices are created using the make() function. The make() function will create a slice of a certain type with a certain length and capacity. The make() function can be used two ways when creating a slice. With only two parameters, the length and capacity are the same. With three parameters, you can specify a maximum capacity larger than the length. Here are two of the make() function declarations:
make([]T, lengthAndCapacity)
make([]T, length, capacity)
A nil slice can be created with a capacity and length of 0. There is no underlying array associated with a nil slice. Here is a short example program demonstrating how to create and inspect a slice:
package main
import "fmt"
func main() {
// Create a nil slice
var mySlice []byte
// Create a byte slice of length 8 and max capacity 128
mySlice = make([]byte, 8, 128)
// Maximum capacity of the slice
fmt.Println("Capacity:", cap(mySlice))
// Current length of slice
fmt.Println("Length:", len(mySlice))
}
You can also append to a slice using the built-in append() function.
Append can add one or more elements at a time. The underlying array will be resized if necessary. This means that the maximum capacity of a slice can be increased. When a slice increases its underlying capacity, creating a larger underlying array, it will create the array with some extra space. This means that if you surpass a slice's capacity by one, it might increase the array size by four. This is done so that the underlying array has room to grow to reduce the number of times the underlying array has to be resized, which may require moving memory around to accommodate the larger array. It could be expensive to resize an array every time just to add a single element. The slice mechanics will automatically determine the best size for resizing.
This code sample provides various examples of working with slices:
package main
import "fmt"
func main() {
var mySlice []int // nil slice
// Appending works on nil slices.
// Since nil slices have zero capacity, and have
// no underlying array, it will create one.
mySlice = append(mySlice, 1, 2, 3, 4, 5)
// Individual elements can be accessed from a slice
// just like an array by using the square bracket operator.
firstElement := mySlice[0]
fmt.Println("First element:", firstElement)
// To get only the second and third element, use:
subset := mySlice[1:4]
fmt.Println(subset)
// To get the full contents of a slice except for the
// first element, use:
subset = mySlice[1:]
fmt.Println(subset)
// To get the full contents of a slice except for the
// last element, use:
subset = mySlice[0 : len(mySlice)-1]
fmt.Println(subset)
// To copy a slice, use the copy() function.
// If you assign one slice to another with the equal operator,
// the slices will point at the same memory location,
// and changing one would change both slices.
slice1 := []int{1, 2, 3, 4}
slice2 := make([]int, 4)
// Create a unique copy in memory
copy(slice2, slice1)
// Changing one should not affect the other
slice2[3] = 99
fmt.Println(slice1)
fmt.Println(slice2)
}