Go 語言中的切片
本位主要介紹一下 Go 語言中可變長度的"數組"——切片(slice)。數組有數組的用處,但是其不可變長度的特性,注定了在大多場景下不是很受歡迎。在大多數場景下我們都會選擇更加靈活的切片。
1. 切片的創建
切片的聲明方式和數組類似,寫法上看就是聲明一個沒有長度的數組:var 切片名 []切片類型
。其中切片類型可以是切片本身,也就是切片的切片,就構成了多維的切片。
切片在使用之前必須要初始化,它沒有零值。聲明后它的值是?nil,這是因為它的底層實現是一個指向數組的指針,在你給它存入一個數組的地址之前,它只能是?nil。
代碼示例:
代碼塊
- 1?
package main
- 2
- 3?
import (
- 4? ? ? ? ? ?
"fmt"
- 5?
)
- 6
- 7?
func main() {
- 8? ? ? ? ? ?
var a []int
- 9? ? ? ? ? ?
fmt.Println("初始化前:", a)
- 10? ? ? ? ??
a = make([]int, 5, 10)
- 11? ? ? ? ?
fmt.Println("初始化后:", a)
- 12? ? ? ? ?
a[4] = 5
- 13? ? ? ? ?
fmt.Println(" 賦值后:", a)
- 14? ? ? ? ?
a[5] = 6
- 15? ? ? ? ?
fmt.Println("賦值后:", a)
- 16?
}
- 第 8 行:聲明一個int類型的切片。
- 第 10 行:聲明一個長度為5,切片容量為10的切片。其中容量可以不傳,默認會和長度相等。長度為切片真正有值的位置,會初始化零值。
- 第 12 行:給切片的第 5 個位置賦值。
- 第 14 行:給切片的第 6 個位置賦值,但是切片的長度為5,所以會報越界的錯誤。
執行結果:
2. 切片的截取
切片之所以被叫做切片是有原因的,它可以從任意長度開始切,切到任意長度為止,然后這一段拿出來就是一個新的切片。切割形式為切片名(s)[起始下標(begin):結束下標(end):最大容量(max)]
。
Tips:截取到的切片包含起始下標(begin),不包含結束下標(end)。
切片截取形式表
操作 | 含義 |
---|---|
s[begin??max] | 截取切片s從begin到end的數據,構成一個容量為max-begin,長度為begin-end的切片。(用的不多) |
s[begin:end] | 截取切片s從begin到end的數據,構成一個容量和長度均為begin-end的切片。 |
s[begin:] | 截取切片s從begin到最后的數據,構成一個容量和長度均為len(s)-end的切片。 |
s[:end] | 截取切片s從0到最后的數據,構成一個容量和長度均為end-0的切片。 |
代碼示例:
代碼塊
- 1?
package main
- 2
- 3?
import (
- 4? ? ? ? ? ?
"fmt"
- 5?
)
- 6
- 7?
func main() {
- 8? ? ? ? ?
var a = []int{1, 2, 3, 4, 5}
- 9? ? ? ? ?
fmt.Println("a[1:3]=", a[1:3])
- 10? ? ? ?
fmt.Println("a[1:]=", a[1:])
- 11? ? ? ?
fmt.Println("a[:3]=", a[:3])
- 12?
}
- 第 8 行:直接定義一個值為?
[1,2,3,4,5]
?的切片,切片長度和容量會根據切片的值自動生成。例如本行代碼定義的切片就是長度和容量均為5。 - 第 9 行:取切片下標從1開始到3之前的值,生成新切片。
- 第 10 行:取切片下標從1開始到最后的值,生成新切片。
- 第 11 行:取切片下標從0開始到3的值,生成新切片。
執行結果:
3. 切片的追加
切片使用一個 Go 語言的內置函數append(切片,待添加的值)
,來進行切片末尾元素的追加。
代碼示例:
代碼塊
- 1?
package main
- 2
- 3?
import (
- 4? ? ? ? ?
"fmt"
- 5?
)
- 6
- 7?
func main() {
- 8? ? ? ? ?
var a = []int{1, 2, 3, 4, 5}
- 9? ? ? ? ?
a = append(a, 6)
- 10? ? ? ?
fmt.Println(a)
- 11? ? ? ?
a = append(a, 7, 8)
- 12? ? ? ?
fmt.Println(a)
- 13? ? ? ?
b := []int{9, 10}
- 14? ? ? ?
a = append(a, b...)
- 15? ? ? ?
fmt.Println(a)
- 16?
}
- 第 9 行:在切片 a 的末尾追加一個元素 6。
- 第 11 行:在切片 a 的末尾連續追加兩個元素 7 和 8。append?中待添加的值可以是?多個,其中使用?
,
?隔開。 - 第 14 行:在切片 a 的末尾追加切片 b。當 append 中待添加的元素是一個數組或者切片時,在其后面添加?
...
?就可以全部追加到切片末尾。
執行結果:
4. 切片的長度和容量
在切片中可以使用len()
獲取切片中元素的數量,也就是切片的長度。使用cap()
可以獲取切片引用的數組的長度,也就切片的容量。切片的容量一般大于等于長度,容量會隨著長度的增長而增長。
在初始化一個切片的時候其實時給切片引用了一個數組,然后容量就是這個數組的長度,然后如果切片的長度超過了切片的容量,它就會讓切片引用一個容量更大數組來存放這些元素。
代碼塊
- 1?
package main
- 2
- 3?
import (
- 4? ? ? ? ?
"fmt"
- 5?
)
- 6
- 7?
func main() {
- 8? ? ? ? ?
var a = []int{1, 2, 3, 4, 5}
- 9? ? ? ? ?
fmt.Printf("a的地址%p,a的長度%d,a的容量%dn", a, len(a), cap(a))
- 10? ? ? ?
a = append(a, 6)
- 11? ? ? ?
fmt.Printf("a的地址%p,a的長度%d,a的容量%dn", a, len(a), cap(a))
- 12? ? ? ?
a = append(a, 7, 8)
- 13? ? ? ?
fmt.Printf("a的地址%p,a的長度%d,a的容量%dn", a, len(a), cap(a))
- 14? ? ? ?
b := []int{9, 10, 11}
- 15? ? ? ?
a = append(a, b...)
- 16? ? ? ?
fmt.Printf("a的地址%p,a的長度%d,a的容量%dn", a, len(a), cap(a))
- 17?
}
執行結果:
從執行結果可以看到,在切片a每次添加的元素要超過它的容量時,它的地址就會發生改變,其實就是讓它引用了一個新的容量更大的數組。
5. 小結
本文主要介紹了切片的使用,有以下注意事項:
- 切片在使用前需要初始化;
- 切片的本質是一個指針數組,但是它的地址會隨著長度超過容量而改變;
- 在應用場景中一般都使用切片。
文章來源于網絡,侵刪!