Skip to main content

切片 Slices

Slices reference arrays, slices is kind of a view into array.

Definition

与 Javascript 中的 Array, python 中的 list 类似,唯一不同的是 Golang 中的 Slice 拥有固定长度。

Example: [2, 3, 1] with index [0, 1, 2]
在 Golang 中 type 是 [3]int, an array of three integers。

var myInts [10]int

primes := [6]int{2, 3, 5, 7, 11, 13}

func getMessageWithRetries() [3]string {
return [3]string {
"click here to sign up",
"pretty please click here",
"we beg you to sign up",
}
}

Slice in Go

99times out of 100 you will use a slice instead of an array when working with ordered lists.

Arrays are fiexed in size. Once you make an array like [10]int you can't add an 11th element.

A slice is dynamically-sized, flexible view of the elements of an array.

Slices always have an underlying array, though it isn't always spcified explicityly. To explicityly create a slice on top of an array we can do:

primes := [6]int{2, 3, 5, 7, 11, 13}
mySlice := primes[1:4]
// mySlice = {3, 5, 7}

The syntax is:

arrayname[lowIndex:highIndex]
arrayname[lowIndex:]
arrayname[:highIndex]
arrayname[:]

Make

Definition

Most of the tiem we don't need to think about underlying array of a slice. We can create a new slice using the 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)

Slices created with make will be filled with the zero value of the type.

If we want to create a slice with a specific set of values, we can use a slice literal:

mySlice := []string{"I", "love", "Go"}

Note that the array brackets do not have a 3 in them. If they did, you'd have an array instead of a slice.

Assignment

func getMessageCosts(messages []string) []float64 {
costs := make([]float64, len(messages))
if i := 0; i < len(messages); i++ {
message := messages[i]
cost := float64(len(message)) * 0.01
costs[i] = cost
}
return costs
}

Length

The length of a lsice is simply the number of elements it contains. It is accessed using the built-in len() function.

mySlice := []string{"I", "love", "Go"}
fmt.Println(len(mySlice)) // 3

Capacity

The capacity of a slice is the number of elements in the underlying array, counting from the first element in first element in the slice. It is accessed using the built-in cap() function:

mySlice := []string{"I", "love", "Go"}
fmt.Println(cap(mySlice)) // 3

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.

underlying principle (When a slice grow the size)

可变参数 Variadic

增加 Append

The built-in append function is used to dynamically add elements to a slice:

func append(slice []Type, elems ...Type) []Type

If the underlying array is not large enough, append() will create a new underlying array and point the slice to it.

Notice that append() is variadic, the following are all valid:

slice = append(slice, oneThing)
slice = append(slice, firstThing, secondThing)
slice = append(slice, anotherSlice...)

Assignment

type Cost struct {
day int
value float64
}
func getCostsByDay(costs []cost) []float64 {
costsByDay := []float64{}
for i := 0; i< len(cost); i++ {
cost := costs[i]
if cost.day >= len(costsByDay) {
costsByDay = append(costsByDay, 0.0)
}
costsByDay[cost.day] += cost.value
}
return costsByDay
}

Slice of slices

Slices can hold other slices, effectively creating a matrix, or a 2D slice.

rows := [][]int{}
func createMatrix(rows, cols int) [][]uint {
matrix := make([][]int, 0)
for i := 0; i < rows; i++ {
row := make ([]int, 0)
for j := 0; j < cols; j++ {
row = append(row, i*j)
}
matrix = append(matrix, row)
}
}

Tricky slices

The append() function chnages the underlying array of its parameter AND returns a new slice. This means that using append() on anything other than itself is usually a BAD idea.

// don't do this !
someSLice = append(otherSlice, element)

Range

Go provides syntactic suger to iterate easily over elements of slice:

for INDEX, ELEMENT := range SLICE {

}
fruits := []string{"apple", "banana", "grape"}
for i, fruit := range fruits {
fmt.Prinln(i, fruit)
}
// 0 apple
// 1 banana
// 2 grape