這一節,我們來討論更多關於Slice
的用法。
nil
切片與空切片
nil
切片
var s []int
fmt.Println(s == nil) // 輸出 true
fmt.Println(len(s),cap(s)) // 輸出:0 0
複製程式碼
上面這段程式碼宣告瞭一個nil
切片s
,其實,切片的零值就是nil
。為什麼?通過上一節我們知道,因為切片就是一個陣列的引用。切片的型別在初始化時已經確認,就是[]Type
,上面的程式碼就宣告瞭[]int
型別的nil
切片s
。nil
切片的指向底層陣列的指標為nil
。
空切片
如何宣告空切片?有兩種方式:
// 1、使用 make 建立空的整型切片
s := make([]int, 0)
// 2、使用切片字面量建立空的整型切片
s := []int{}
fmt.Println(s) // 輸出:[]
fmt.Println(len(s),cap(s)) // 輸出:0 0
複製程式碼
通過上面程式碼可以得出,與nil
切片一樣,空切片的長度和容量也都是0,說明切片底層的陣列大小為0,是一個空陣列(沒有分配任何的儲存空間)。
不管是使用
nil
切片還是空切片,對其呼叫內建函式append
、len
和cap
的效果都是一樣的。
copy
函式
Go提供了內建函式copy
,可以講一個切片複製到另一個切片。函式原型:
func copy(dst, src []Type) int
複製程式碼
dst
是目標切片,src
是源切片,函式返回兩者長度的最小值。
var s1 []int
s2 := []int{1, 2, 3}
s3 := []int{4, 5, 6, 7}
s4 := []int{1, 2, 3}
// 1、
n1 := copy(s1, s2)
fmt.Printf("n1=%d, s1=%v, s2=%v
", n1, s1, s2)
fmt.Println("s1 == nil", s1 == nil)
// 2、
n2 := copy(s2, s3)
fmt.Printf("n2=%d, s2=%v, s3=%v
", n2, s2, s3)
// 3、
n3 := copy(s3, s4)
fmt.Printf("n3=%d, s3=%v, s4=%v
", n3, s3, s4)
複製程式碼
輸出:
n1=0, s1=[], s2=[1 2 3]
s1 == nil true
n2=3, s2=[4 5 6], s3=[4 5 6 7]
n3=3, s3=[1 2 3 7], s4=[1 2 3]
複製程式碼
上面程式碼生宣告瞭nil
切片s1
和三個非空切片s2
、s3
和s4
。從第一塊程式碼塊可以看到,因為s1
是nil
切片,執行完copy
操作之後,s1
依然還是nil
。這有別於append
函式:
var s1 []int
s2 := []int{1, 2, 3}
s1 = append(s1, s2...)
fmt.Println(s1) // 輸出:[1 2 3]
複製程式碼
第二段程式碼:由於s2
的長度是3,s3
的長度是4,所以執行copy
操作只會從s3
複製3個元素至s2
。copy
只會複製,不會追加。
第三段程式碼也是同樣的道理。
函式間傳遞切片
切片在函式間以值的方式傳遞。由於切片的尺寸很小(在 64 位架構的機器上,一個切片需要 24 位元組的記憶體:指標欄位、長度和容量欄位各需要 8 位元組),在函式間複製和傳遞切片成本也很低。切片發生複製時,底層陣列不會被複制,陣列大小也不會有影響。
func main() {
s := []int{0, 1, 2, 3, 4, 5}
fmt.Printf("%p
", &s)
modify(s)
fmt.Println(s)
}
func modify(s []int) {
fmt.Printf("%p
", &s)
s[1] = 10
}
複製程式碼
輸出:
0xc000086020
0xc000086040
[0 10 2 3 4 5]
複製程式碼
我們可以看到,原切片地址和傳遞之後的切片的地址是不一樣的,說明發生了複製;在函式modify
中修改了切片一個值,原切片的值也隨之改變了,說明這兩個切片是共享底層陣列的。
在函式間傳遞切片非常高效,而且不需要傳遞指標和處理複雜的語法,只需要複製切片,按自己的業務修改資料,最後傳遞迴一個新的切片副本即可,這也是為什麼函式間使用切片傳參,而不是陣列傳參的原因。
刪除切片中的元素
Go沒有提供刪除切片元素的函式,然而,我們可以使用一些“黑科技”達到這樣的目的。
s := []int{1, 2, 3, 4, 5, 6}
s = append(s[:2], s[3:]...) // 刪除索引為2的元素
fmt.Println(s)
複製程式碼
輸出:
[1 2 4 5 6]
複製程式碼
通過這兩節詳解,相信你已經掌握了Slice
,建議大家要多多練習!
(全文完)
原創文章,若需轉載請註明出處!
歡迎掃碼關注公眾號「Golang來了」或者移步 www.seekload.net,檢視更多精彩文章。
關注公眾號「Golang來了」,獲取最新文章!