Slices and arrays
Slices wrap arrays to give a more general, powerful, and convenient interface to sequences of data.
Slices hold references to an underlying array
Defining array:
var arr [5]int
Defining slice:
var slice []int
Slices in memory and how they work with hardware
- RAM is just a mapping of addresses to data
- slices and the arrays that they are built on top of are contiguously stored in memory instead of randomly, which is good for performance
- however, when growing a slice whose underlying array is not large enough, the underlying array is reallocated to a new point in RAM and the slice is adjusted to point to the new array (copying data from memory to memory is not efficient)
Make
Most of the time we don't have to think about the underlying array of a slice, just create new slice using make
function
// func make([]T, len, cap) []T
mySlice := make([]int, 5, 10)
// the capacity argument is usually omitted and defaults to the length
mySlice := make([]int, 5)
// creating slice w specific set of values using slice literal
mySlice := []string{"I", "love", "go"}
Length and capacity
Length of a slice is simply the number of elements it contains.
Capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice
mySlice := []string{"I", "love", "go"}
fmt.Println(len(mySlice)) // 3
mySlice := []string{"I", "love", "go"}
fmt.Println(cap(mySlice)) // 3
Generally speaking, unless you're hyper-optimizing the memory usage of your program, you don't need to worry about the capacity of a slice because it will automatically grow as needed.
Variadic
Many functions, especially those in the standard library, can take an arbitrary number of final arguments. This is accomplished by using the "..." syntax in the function signature.
A variadic function receives the variadic arguments as a slice
func concat(strs ...string) string {
final := ""
// strs is just a slice of strings
for i := 0; i < len(strs); i++ {
final += strs[i]
}
return final
}
func main() {
final := concat("Hello ", "there ", "friend!")
fmt.Println(final)
// Output: Hello there friend!
}
The Spread operator allows us to pass a slice into a variadic function
func printStrings(strings ...string) {
for i := 0; i < len(strings); i++ {
fmt.Println(strings[i])
}
}
func main() {
names := []string{"bob", "sue", "alice"}
printStrings(names...)
}
Append
append()
built in function that is used to dynamically add ele to slices
- The append() function changes the underlying array of its parameter AND returns a new slice
append()
on anything other that itself is usually a bad idea
- if the underlying array is not large enough, it will be reallocated to a new point in memory and point the slice to it
slice = append(slice, oneThing)
slice = append(slice, firstThing, secondThing)
slice = append(slice, anotherSlice...)