切片(slice)
是乙個擁有相同型別元素的可變長度的序列。它是基於陣列型別做的一層封裝。它非常靈活,支援自動擴容。切片是乙個引用型別,它的內部結構包含位址
、長度
和容量
。切片一般用於快速地操作一塊資料集合。
陣列的長度是固定的並且陣列長度屬於型別的一部分,所以陣列有很多的侷限性。
1 func arraysum(x [3]int) int 6 return sum 7 }
這個求和函式只能接受[3]int
型別,其他的都不支援。 再比如,
1 a := [3]int
陣列a中已經有三個元素了,我們不能再繼續往陣列a中新增新元素了。
切片的定義
宣告切片型別的基本語法如下:
1 var name t
其中,舉個例子:
1 func main() //宣告乙個整型切片並初始化 5 var c = bool //宣告乙個布林切片並初始化 6 var d = bool //宣告乙個布林切片並初始化 7 fmt.println(a) // 8 fmt.println(b) // 9 fmt.println(c) //[false true] 10 fmt.println(a == nil) //true 11 fmt.println(b == nil) //false 12 fmt.println(c == nil) //false 13 // fmt.println(c == d) //切片是引用型別,不支援直接比較,只能和nil比較 14 }
切片的長度和容量
切片擁有自己的長度和容量,我們可以通過使用內建的len()函式求長度,使用內建的cap()函式求切片的容量。
基於陣列定義切片
由於切片的底層就是乙個陣列,所以我們可以基於陣列定義切片。
1 func main() 4 b := a[1:4] //基於陣列a建立切片,包括元素a[1],a[2],a[3] 5 fmt.println(b) //[56 57 58] 6 fmt.printf("type of b:%t\n", b) //type of b:int 7 }
還支援如下方式:
1 c := a[1:] //[56 57 58 59] 2 d := a[:4] //[55 56 57 58] 3 e := a[:] //[55 56 57 58 59]
切片再切片
除了基於陣列得到切片,我們還可以通過切片來得到切片。
1 func main() 4 fmt.printf("a:%v type:%t len:%d cap:%d\n", a, a, len(a), cap(a)) 5 b := a[1:3] 6 fmt.printf("b:%v type:%t len:%d cap:%d\n", b, b, len(b), cap(b)) 7 c := b[1:5] 8 fmt.printf("c:%v type:%t len:%d cap:%d\n", c, c, len(c), cap(c)) 9 }
輸出:1 a:[北京 上海 廣州 深圳 成都 重慶] type:[6]string len:6 cap:6 2 b:[上海 廣州] type:string len:2 cap:5 3 c:[廣州 深圳 成都 重慶] type:string len:4 cap:4
注意:對切片進行再切片時,索引不能超過原陣列的長度,否則會出現索引越界的錯誤。
使用make()函式構造切片
我們上面都是基於陣列來建立的切片,如果需要動態的建立乙個切片,我們就需要使用內建的make()
函式,格式如下:
1 make(t, size, cap)
其中:舉個例子:
1 func main()
上面**中a
的內部儲存空間已經分配了10個,但實際上只用了2個。 容量並不會影響當前元素的個數,所以len(a)
返回2,cap(a)
則返回該切片的容量。
切片的本質
切片的本質就是對底層陣列的封裝,它包含了三個資訊:底層陣列的指標、切片的長度(len)和切片的容量(cap)。
舉個例子,現在有乙個陣列a := [8]int
,切片s1 := a[:5]
,相應示意圖如下。
切片s2 := a[3:6]
,相應示意圖如下:
切片不能直接比較
切片之間是不能比較的,我們不能使用==
操作符來判斷兩個切片是否含有全部相等元素。 切片唯一合法的比較操作是和nil
比較。 乙個nil
值的切片並沒有底層陣列,乙個nil
值的切片的長度和容量都是0。但是我們不能說乙個長度和容量都是0的切片一定是nil
,例如下面的示例:
1 var s1 int //len(s1)=0;cap(s1)=0;s1==nil 2 s2 := int{} //len(s2)=0;cap(s2)=0;s2!=nil 3 s3 := make(int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
所以要判斷乙個切片是否是空的,要是用len(s) == 0
來判斷,不應該使用s == nil
來判斷。
切片的賦值拷貝
下面的**中演示了拷貝前後兩個變數共享底層陣列,對乙個切片的修改會影響另乙個切片的內容,這點需要特別注意。
1 func main() 8
切片遍歷
切片的遍歷方式和陣列是一致的,支援索引遍歷和for range
遍歷。
1 func main() 3 4 for i := 0; i < len(s); i++ 7 8 for index, value := range s 11 }
輸出:1 [0] len:1 cap:1 ptr:0xc0000a8000 2 [0 1] len:2 cap:2 ptr:0xc0000a8040 3 [0 1 2] len:3 cap:4 ptr:0xc0000b2020 4 [0 1 2 3] len:4 cap:4 ptr:0xc0000b2020 5 [0 1 2 3 4] len:5 cap:8 ptr:0xc0000b6000 6 [0 1 2 3 4 5] len:6 cap:8 ptr:0xc0000b6000 7 [0 1 2 3 4 5 6] len:7 cap:8 ptr:0xc0000b6000 8 [0 1 2 3 4 5 6 7] len:8 cap:8 ptr:0xc0000b6000 9 [0 1 2 3 4 5 6 7 8] len:9 cap:16 ptr:0xc0000b8000 10 [0 1 2 3 4 5 6 7 8 9] len:10 cap:16 ptr:0xc0000b8000
從上面的結果可以看出:
切片numslice的容量按照1,2,4,8,16這樣的規則自動進行擴容,每次擴容後都是擴容前的2倍。
切片的擴容策略
1 newcap := old.cap 2 doublecap := newcap + newcap 3 if cap > doublecap else else 14 // set newcap to the requested cap when 15 // the newcap calculation overflowed. 16 if newcap <= 0 19 } 20 }
從上面的**可以看出以下內容:
需要注意的是,切片擴容還會根據切片中元素的型別不同而做不同的處理,比如int
和string
型別的處理方式就不一樣。
使用copy()函式複製切片
首先我們來看乙個問題:
1 func main() 3 b := a 4 fmt.println(a) //[1 2 3 4 5] 5 fmt.println(b) //[1 2 3 4 5] 6 b[0] = 1000 7 fmt.println(a) //[1000 2 3 4 5] 8 fmt.println(b) //[1000 2 3 4 5] 9 }
由於切片是引用型別,所以a和b其實都指向了同一塊記憶體位址。修改b的同時a的值也會發生變化。
go語言內建的copy()
函式可以迅速地將乙個切片的資料複製到另外乙個切片空間中,copy()
函式的使用格式如下:
1 copy(destslice, srcslice t)
其中:舉個例子:
1 func main() 4 c := make(int, 5, 5) 5 copy(c, a) //使用copy()函式將切片a中的元素複製到切片c 6 fmt.println(a) //[1 2 3 4 5] 7 fmt.println(c) //[1 2 3 4 5] 8 c[0] = 1000 9 fmt.println(a) //[1 2 3 4 5] 10 fmt.println(c) //[1000 2 3 4 5] 11 }
從切片中刪除元素
go語言中並沒有刪除切片元素的專用方法,我們可以使用切片本身的特性來刪除元素。 **如下:
歸類 :go語言
go語言基礎 切片 slice
理解為變長的陣列 a 切片建立 s1 int s2 make t,len,cap arr 5 int s3 arr start end 切割陣列 start,end s4 arr b 切片的型別 資料型別 切片屬於引用型別 s1 int s2 s1 packagemain import fmt fu...
Go語言基礎語法 切片
go中的切片可對標python中的切片,是對陣列的抽象,可以理解為動態陣列,可通過乙個不指定大小的陣列來宣告乙個切片 go中切片的幾種常用語法的示例程式如下 一 通過make函式定義切片及使用len 和cap 函式 例項 package main import fmt func main func ...
go語言基礎之切片
1 切片的長度和容量 流程分析 示例 package main 必須有個main包 import fmt func main s a 0 3 5 fmt.println s s fmt.println len s len s 長度 3 0 fmt.println cap s cap s 容量 5 0...