? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?切片
切片定義:
切片(slice)是對數(shù)組一個連續(xù)片段的引用认境,所以切片是一個引用類型。
注意事項:
切片的長度可以在運行時修改挟鸠,最小為0叉信,最大為相關數(shù)組的長度:切片是一個長度可變的數(shù)組。
切片容量:
cap()
切片聲明:
var slice []type (不需要說明長度)
切片初始化:
arr := [5]int{1, 2, 3, 4, 5} ? //數(shù)組
var sl []int = arr[0:3] ? ?//var sl []int = arr[:]等于完整的arr數(shù)組
or:
sl := []int{1, 2, 3, 4, 5} ?//聲明并初始化了一個切片
切片的組成:
指針艘希、長度(len)硼身、容量(cap)
指針:指向第一個slice元素對應的底層數(shù)組元素的內存地址。注:slice的第一個元素不一定就是數(shù)組的第一個元素覆享。
用make()創(chuàng)建一個切片:
slice := make([]type, len, [cap])
ep:
sl := make([]int, 50, 100) ?等價于 sl := new([100]int)[0:50]
new()和make()的區(qū)別:
new(T):為每個新的類型T分配一片內存佳遂,初始化為0并且返回類型為*T的內存地址:這種方法返回一個指向類型為T,值為0的地址的指針(適用:值類型和結構體)
make(T):返回一個類型為T的初始值(適用:切片淹真、map和channel)
ep:
arr := new([10]int)? //&[0 0 0 0 0]
arr2 := make([]int, 5)? //[0 0 0 0 0]
切片重組:
sl:=make([]type, start_length, capacity)
改變切片長度(start_length)的過程稱之為切片重組reslicing
方法:sl = sl[0:len(sl)+1]
切片可以反復擴展直到占據(jù)整個相關數(shù)組讶迁,如果到len(sl)+1 > capacity則會報錯:panic: runtime error: slice bounds out of range
切片的復制:
sl_form := []int{1,2,3}
sl_to := make([]int, 10)
new := copy(sl_to, sl_from)? //[1 2 3 0 0 0 0 0 0 0]
coyp函數(shù):第一個參數(shù):to,第二個參數(shù):from核蘸, 返回:拷貝的個數(shù)巍糯。 copy操作流程:把from切片的元素從第一個開始一個一個的拷貝到,to切片里面(to切片也是從第一個元素開始接受的)客扎,如果想向一個切片增加一個元素或者一個切片祟峦,則需要用到append函數(shù)。
切片的追加:
append函數(shù): 第一個參數(shù):被追加的切片徙鱼;第二個參數(shù):需要追加的數(shù)據(jù)宅楞;返回:被追加后新的切片
注意: append 在大多數(shù)情況下很好用,但是如果你想完全掌控整個追加過程袱吆,你可以實現(xiàn)一個這樣的 AppendByte 方法:
funcAppendByte(slice[]byte,data ...byte) []byte{
? ? ? ? m :=len(slice)
? ? ? ? n := m +len(data)
? ? ? ? if n >cap(slice) {
? ? ? ? // if necessary, reallocate
? ? ? ? // allocate double what's needed, for future growth.
? ? ? ? newSlice :=make([]byte,(n +1) *2)
? ? ? ? copy(newSlice,slice)
? ? ? ? slice= newSlice
? ? }
? ? slice=slice[0:n]
? ? copy(slice[m:n],data)
? ? returnslice
}
從字符串生成字節(jié)切片:
一個字符串本質上是一個字節(jié)數(shù)組厌衙,所以可以像對普通數(shù)組那樣,生成切片绞绒,而字符串生成的數(shù)組則就是字節(jié)數(shù)組婶希。
切片和垃圾回收:
切片的底層指向一個數(shù)組,該數(shù)組的實際體積可能要大于切片所定義的體積蓬衡。只有在沒有任何切片指向的時候喻杈,底層的數(shù)組內層才會被釋放,這種特性有時會導致程序占用多余的內存狰晚。
append 函數(shù)常見操作:
將切片 b 的元素追加到切片 a 之后:a = append(a, b...) ?//這里三個點表示把b切片的所有數(shù)據(jù)追加到a切片后面
復制切片 a 的元素到新的切片 b 上:
b =make([]T,len(a))copy(b, a)
刪除位于索引 i 的元素:a = append(a[:i], a[i+1:]...)
切除切片 a 中從索引 i 至 j 位置的元素:a = append(a[:i], a[j:]...)
為切片 a 擴展 j 個元素長度:a = append(a, make([]T, j)...)
在索引 i 的位置插入元素 x:a = append(a[:i], append([]T{x}, a[i:]...)...)
在索引 i 的位置插入長度為 j 的新切片:a = append(a[:i], append(make([]T, j), a[i:]...)...)
在索引 i 的位置插入切片 b 的所有元素:a = append(a[:i], append(b, a[i:]...)...)
取出位于切片 a 最末尾的元素 x:x, a = a[len(a)-1], a[:len(a)-1]
將元素 x 追加到切片 a:a = append(a, x)
使用slice時需要注意的問題:
arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s1 := arr[2:6]
s2 := arr[5:10]
s2[0] = 99
fmt.Println(s1, s2)? // [3 4 5 99] [99 7 8 9 10] 可以看出s1和s2的重疊部分會在其中一個改變時改變筒饰。
但是:
arr := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s1 := arr[2:6]
s2 := arr[5:10]
s1 = append(s1, 1, 2, 3, 4, 5, 6, 7, 8, 9)
s2[0] = 99
fmt.Println(s1, s2)?
輸出:
[3 4 5 6 1 2 3 4 5 6 7 8 9] [99 7 8 9 10]?
可以看出,s1之前和s2重疊部分的數(shù)據(jù)沒有隨s2的改變而改變壁晒,因為瓷们,append在給s1增加元素時已經(jīng)超出了s1的容量,所以重新為s1分配了一塊連續(xù)的內存,此時s1和s2指向已經(jīng)不是同一塊內存中的數(shù)組了换棚,所以s2的改變時無法影響s1了式镐。
刪除slice中指定的元素
因為slice引用指向底層數(shù)組,數(shù)組的長度不變元素是不能刪除的固蚤,所以刪除的原理就是排除待刪除元素后用其他元素重新構造一個數(shù)組
func? deleteByAppend (i int) []int {?
? ? ? i :=3
? ? ? s := []int{1,2,3,4,5,6,7}
? ? ? s = append(s[:i], s[i+1:]...)
? ? ? ?return s
}
func ?deleteByCopy (i int) []int { ? ?
? ? ? ?s := []int{1,2,3,4,5,6,7}
? ? ? ?copy(s[i:], s[i+1:])? ??
? ? ? ? s = s[:len(s)-1]
? ? ? ? return s
}