什么是切片
切片是 Golang 中比較特殊的數(shù)據(jù)結(jié)構(gòu)侄榴,這種數(shù)據(jù)結(jié)構(gòu)更便于使用和管理數(shù)據(jù)集合椭微。簡單的說,切片就是一種簡化版的動(dòng)態(tài)數(shù)組缠局。因?yàn)閯?dòng)態(tài)數(shù)組的長度不固定,所以切片的長度自然也就不能是類型的組成部分了考润。切片是圍繞動(dòng)態(tài)數(shù)組的概念構(gòu)建的狭园,是對(duì)數(shù)組的抽象。數(shù)組雖然有適用的地方糊治,但是數(shù)組的類型和操作都不夠靈活妙啃,因此在 Go 代碼中數(shù)組使用的并不是很多,而切片則使用的相當(dāng)廣泛,理解切片的原理和用法相當(dāng)重要揖赴。
切片的內(nèi)部結(jié)構(gòu)
我們先來看看切片的結(jié)構(gòu)定義馆匿,即 reflect.SliceHeader:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
由切片的結(jié)構(gòu)定義可知,切片的結(jié)構(gòu)由三個(gè)信息組成:
指針燥滑,指向底層數(shù)組中切片指定的開始位置
長度渐北,即切片的長度
最大長度,也就是切片開始位置到數(shù)組的最后位置的長度
下圖給出了切片 x := [2, 3, 5, 7, 9, 11, 13, 15] 和 y := [1:3] 兩個(gè)切片對(duì)應(yīng)的內(nèi)存結(jié)構(gòu)铭拧。
切片的創(chuàng)建和初始化
讓我們看看切片有哪些創(chuàng)建和初始化的方式:
var(
a []int // nil 切片赃蛛,和 nil 相等,一般用來表示一個(gè)不存在的切片
b = []int{} // 空切片搀菩,和 nil 不相等呕臂,一般用來表示一個(gè)空的集合
c = []int{1, 2, 3, 4} // 有 4 個(gè)元素的切片,len 和 cap 都為 4
d = c[:2] // 有 2 個(gè)元素的切片肪跋,len 為 2歧蒋,cap 為 4
e = c[0:2:cap(c)] // 有 2 個(gè)元素的切片,len 為 2州既,cap 為 4
f = c[:0] // 有 0 個(gè)元素的切片谜洽,len 為 0,cap 為 4
g = make([]int, 3) // 有 3 個(gè)元素的切片吴叶,len 和 cap 都為 3
h = make([]int, 3, 5) // 有 3 個(gè)元素的切片阐虚,len 為 3,cap 為 5
i = make([]int, 0, 5) // 有 0 個(gè)元素的切片蚌卤,len 為 0实束,cap 為 5
)
使用 Golang 內(nèi)置的函數(shù) len() 可以查看切片中有效元素的長度,內(nèi)置的函數(shù) cap() 可以查看切片容量大小逊彭。
修改切片
切片沒有自己的任何數(shù)據(jù)咸灿,它只是底層數(shù)組的一個(gè)表示。對(duì)切片所做的任何修改都將反映在底層數(shù)組中诫龙。
示例代碼:
package main
import (
"fmt"
)
func main() {
darr := [...]int{57, 89, 90, 82, 100, 78, 67, 69, 59}
dslice := darr[2:5]
fmt.Println("array before",darr)
for i := range dslice {
dslice[i]++
}
fmt.Println("array after",darr)
}
運(yùn)行結(jié)果:
array before [57 89 90 82 100 78 67 69 59]
array after [57 89 91 83 101 78 67 69 59]
當(dāng)多個(gè)片共享相同的底層數(shù)組時(shí),每個(gè)元素所做的更改將在數(shù)組中反映出來鲫咽。
示例代碼:
package main
import (
"fmt"
)
func main() {
numa := [3]int{78, 79 ,80}
nums1 := numa[:] //creates a slice which contains all elements of the array
nums2 := numa[:]
fmt.Println("array before change 1",numa)
nums1[0] = 100
fmt.Println("array after modification to slice nums1", numa)
nums2[1] = 101
fmt.Println("array after modification to slice nums2", numa)
}
運(yùn)行結(jié)果:
array before change 1 [78 79 80]
array after modification to slice nums1 [100 79 80]
array after modification to slice nums2 [100 101 80]