Go語言基礎 切片

2021-10-25 08:41:55 字數 4674 閱讀 1043

切片(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 }

從上面的**可以看出以下內容:

需要注意的是,切片擴容還會根據切片中元素的型別不同而做不同的處理,比如intstring型別的處理方式就不一樣。

使用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...