起風(fēng)時&李璇 作品
我們總是喜歡拿“順其自然”來敷衍人生道路上的荊棘坎坷,卻很少承認肿轨,真正的順其自然荡澎,其實是竭盡所能之后的不強求,而非兩手一攤的不作為局装。 by 瑞卡斯
引用于:http://wufazhuce.com/one/1353
slice 知識要點
- ** slice 是引用類型坛吁,所以當(dāng)引用改變其中元素的值時,其它的所有引用都會改變該值**铐尚。
- ** slice 在未初始化之前默認為 nil拨脉,長度為 0**。
-
slice 的聲明格式:
var identifier []type
(不需要說明長度)宣增。 -
slice 初始化格式:
4.1.var sliceName []type = arrName[start:end]
(通過數(shù)組初始化切片)玫膀。
4.2.var sliceName []type = make([]type, len, cap)
(cap
可選參數(shù))。
4.3.a := []int(1, 2)
(已知道元素值情況下初始化切片)爹脾。 -
slice 像一個結(jié)構(gòu)體帖旨,這個結(jié)構(gòu)體包含了三個元素
5.1. 一個指針箕昭,指向數(shù)組中 slice 指定的開始位置。
5.2.len
長度解阅,即 slice 的長度落竹。
5.3.cap
最大長度,也就是 slice 開始位置到數(shù)組的最后位置的長度货抄。 - 盡可能的用切片代替數(shù)組
-
使用
make([]type, 0)
實例化一個空的切片述召。
例如:下面示例和視圖
Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
Slice_a := Array_a[2:5]
slice示例圖
slice
和數(shù)組在聲明時的區(qū)別:聲明數(shù)組時,方括號內(nèi)寫明了數(shù)組的長度或使用...自動計算長度蟹地,而聲明slice
時积暖,方括號內(nèi)沒有任何字符。
slice 的一些簡便操作
-
slice 的默認開始位置是
0
怪与,ar[:n]等價于ar[0:n]
夺刑。 -
slice 的第二個序列默認是數(shù)組的長度,
ar[n:]
等價于ar[n:len(ar)]
琼梆。 -
如果從一個數(shù)組里面直接獲取 slice性誉,可以這樣
ar[:]
窿吩,因為默認第一個序列是0
茎杂,第二個是數(shù)組的長度,即等價于ar[0:len(ar)]
纫雁。
slice和array的對應(yīng)關(guān)系圖
func printSliceByRange(s []int) {
for k, v := range s {
fmt.Printf("s[%d]=%d ", k, v)
}
fmt.Println()
}
func printSliceByLen(s []int) {
for i, j := 0, len(s); i < j; i++ {
fmt.Printf("s[%d]=%d ", i, s[i])
}
fmt.Println()
}
/*
數(shù)組[a:b]
創(chuàng)建一個包含數(shù)組的第a個元素到第b-1個元素的切片煌往。
當(dāng)前長度 = b - a
最大容量 = len(數(shù)組) - a
slice是引用類型,所以當(dāng)引用改變其中元素的值時轧邪,其它的所有引用都會改變該值
*/
func main() {
//通過指向一個數(shù)組聲明并初始化slice
arr := [5]int{1, 2, 3, 4, 5}
//等價于sliceA := arr[0:5]
//包含arr的全部元素{1, 2, 3, 4, 5}
//len = 5刽脖,cap = 5
sliceA := arr[:]
//等價于sliceA := arr[0:4]
//包含arr的全部元素{1, 2, 3, 4}
//len = 4,cap = 5
sliceA = arr[:4]
//等價于sliceA := arr[3:5]
//包含arr的全部元素{4, 5}
//len = 2忌愚,cap = 2
sliceA = arr[3:]
//包含arr的全部元素{2, 3, 4}
//len = 3曲管,cap = 4
sliceA = arr[1:4]
//通過make聲明并初始化slice
//指向一個int類型數(shù)組,默認長度為2硕糊,最大容量為10
sliceB := make([]int, 2, 10)
printSliceByRange(sliceA) //s[0]=2 s[1]=3 s[2]=4
printSliceByLen(sliceB) //s[0]=0 s[1]=0
//append函數(shù)會改變slice所引用的數(shù)組的內(nèi)容院水,從而影響到引用同一數(shù)組的其它slice。
//但當(dāng)slice中沒有剩余空間(即(cap-len) == 0)時简十,此時將動態(tài)分配新的數(shù)組空間檬某。
//返回的slice數(shù)組指針將指向這個空間,而原數(shù)組的內(nèi)容將保持不變螟蝙;其它引用此數(shù)組的slice則不受影響恢恼。
sliceA = arr[:]
sliceC := append(sliceA, 6)
printSliceByRange(sliceA) //s[0]=1 s[1]=2 s[2]=3 s[3]=4 s[4]=5
printSliceByRange(sliceC) //s[0]=1 s[1]=2 s[2]=3 s[3]=4 s[4]=5 s[5]=6
}
在閱讀<Golang入門指南>這本書時,對切片又有了一些新認識胰默。
slice 結(jié)合append场斑、copy函數(shù)使用
- 將切片b追加到切片a之后漓踢。
temp_as = append(temp_as, temp_bs...)
- 復(fù)制切片a的元素到新的切片b上。
copy(temp_cs, temp_bs)
- 刪除位于索引i的元素漏隐。
append(temp_as[:i], temp_as[i+1:]...)
- 切除切片a中從索引j至k位置的元素彭雾。
append(temp_as[:j], temp_as[k:]...)
- 將元素b追加到切片a。
append(temp_as, b)
func demo7() {
//將切片b追加到切片a之后
temp_a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
temp_as := temp_a[:]
temp_b := [5]int{10, 11, 12, 13, 14}
temp_bs := temp_b[:]
temp_as = append(temp_as, temp_bs...)
fmt.Println(temp_as) //[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
//復(fù)制切片a的元素到新的切片b上
temp_cs := make([]int, 15)
copy(temp_cs, temp_bs)
fmt.Println(temp_cs) //[10 11 12 13 14 0 0 0 0 0 0 0 0 0 0]
//刪除位于索引5的元素
temp_as = append(temp_as[:5], temp_as[6:]...)
fmt.Println(temp_as) //[0 1 2 3 4 6 7 8 9 10 11 12 13 14]
//切除切片a中從索引3至6位置的元素
temp_as = append(temp_as[:3], temp_as[6:]...)
fmt.Println(temp_as) //[0 1 2 7 8 9 10 11 12 13 14]
//將元素15追加到切片a
temp_as = append(temp_as, 15)
fmt.Println(temp_as) //[0 1 2 7 8 9 10 11 12 13 14 15]
}
切片和垃圾回收
切片的底層指向一個數(shù)組锁保,該數(shù)組的實際體積可能要大于切片所定義的體積薯酝。只有在沒有任何切片指向的時候,底層的數(shù)組內(nèi)層才會被釋放爽柒,這種特性有時會導(dǎo)致程序占用多余的內(nèi)存吴菠。
示例 函數(shù)FindDigits
將一個文件加載到內(nèi)存,然后搜索其中所有的數(shù)字并返回一個切片浩村。
var digitRegexp = regexp.MustCompile("[0-9]+")
func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
return digitRegexp.Find(b)
}
這段代碼可以順利運行做葵,但返回的[]byte
指向的底層是整個文件的數(shù)據(jù)。只要該返回的切片不被釋放心墅,垃圾回收器就不能釋放整個文件所占用的內(nèi)存酿矢。換句話說,一點點有用的數(shù)據(jù)卻占用了整個文件的內(nèi)存怎燥。
想要避免這個問題瘫筐,可以通過拷貝我們需要的部分到一個新的切片中:
func FindDigits(filename string) []byte {
b, _ := ioutil.ReadFile(filename)
b = digitRegexp.Find(b)
c := make([]byte, len(b))
copy(c, b)
return c
}
參考:
https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.2.md