1.說明
1)其本身並不是數組,它指向底層的數組
2)作爲變長數組的替代方案,可以關聯底層數組的局部或全部
3)爲引用類型
4)可以直接創建或從底層數組獲取生成
5)使用len()獲取元素個數,cap()獲取容量
6)一般使用make()創建
7)如果多個slice指向相同底層數組,其中一個的值改變會影響全部
8)切片本身沒有數據,是對數組底層的一個view
2.創建:
make([]T, len, cap)
其中cap可以省略,則容量和len的值相同
len表示存數的元素個數,cap表示容量
代碼實例:直接var s []int形式
package main
import "fmt"
func main() {
var s []int //沒有元素則切片是空的
for i := 0; i < 100; i++ {
s = append(s, i)
}
fmt.Println(s)
}
輸出:
API server listening at: 127.0.0.1:33537
[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99]
使用make創建:
package main
import "fmt"
func main() {
s := make([]int, 10)
for i := 0; i < 10; i++ {
s[i] = i
}
fmt.Println(s)
}
輸出:
API server listening at: 127.0.0.1:21778
[0 1 2 3 4 5 6 7 8 9]
3.方法
1)Reslice
Reslice時所有以唄slice的切片爲準
所有不可以超過唄slice的切片的容量cap()值
索引越界不會導致底層數組的重新分配而是引發錯誤
2)Append
可以在slice尾部追加元素
可以將一個slice追加在另一個slice尾部
如果最終長度爲超過主機到slice的容量則返回原始slice
如果超過追加道德slice 的容量則將重新分配數組並拷貝原始數據
3)Copy
4.代碼實例
package main
import "fmt"
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println("arr[2:6]:", arr[2:6])
fmt.Println("arr[:6]:", arr[:6])
fmt.Println("arr[2:]:", arr[2:])
fmt.Println("arr[:]:", arr[:])
}
輸出:
API server listening at: 127.0.0.1:37693
arr[2:6]: [2 3 4 5]
arr[:6]: [0 1 2 3 4 5]
arr[2:]: [2 3 4 5 6 7 8 9]
arr[:]: [0 1 2 3 4 5 6 7 8 9]
上述代碼中:
arr[2:6]從數組中取值是第2號元素到第5號元素,不包括6號
arr[:6]從頭到第5號元素,不包括6號
arr[2:]從2號元素到結尾,包括2號元素
arr[:]獲取所有元素
實例二
package main
import "fmt"
//參數中數組不加長度,這個就是切片
func updateSlice(s []int) {
s[0] = 999
}
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := arr[2:]
fmt.Println("s1:", s1)
s2 := arr[:]
fmt.Println("s2:", s2)
fmt.Println("after updateSlice(s1)")
updateSlice(s1)
fmt.Println(s1)
fmt.Println(arr)
fmt.Println("after updateSlice(s2)")
updateSlice(s2)
fmt.Println(s2)
fmt.Println(arr)
}
API server listening at: 127.0.0.1:19977
s1: [2 3 4 5 6 7 8 9]
s2: [0 1 2 3 4 5 6 7 8 9]
after updateSlice(s1)
[999 3 4 5 6 7 8 9]
[0 1 999 3 4 5 6 7 8 9]
after updateSlice(s2)
[999 1 999 3 4 5 6 7 8 9]
[999 1 999 3 4 5 6 7 8 9]
這段代碼中updateSlice完成了對數組的數據更新
切片還有一種操作叫做reslice
package main
import "fmt"
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s := arr[:]
fmt.Println(s)
s = s[:5]
fmt.Println(s)
s = s[2:]
fmt.Println(s)
}
輸出:
API server listening at: 127.0.0.1:3798
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4]
[2 3 4]
5.擴展
1)實例說明
看下面一段代碼執行結果是多少:
package main
import "fmt"
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6
fmt.Println(s1)
s2 := s1[3:5]
fmt.Println(s2)
}
輸出:
API server listening at: 127.0.0.1:43832
[2 3 4 5]
[5 6]
上述代碼S的值是2,3,4,5但是s2是s1的切片,爲什麼取值不是s1裏面的內容呢,顯然5和6已經超出了範圍。請看下圖:
有底層數組向上一次是數組arr的內容是0,1,2,3,4,5,6,7那麼s1作爲arr的切片取值下標是2--6也就是說:
s1[0] = 2
s1[1] = 3
s1[2] = 4
s1[3] = 5
s1[4] = 6
s1[5] = 7
s2是s1的切片,取值是s1的3--5下標,對應到數組arr裏面就是arr[5]--arr[6]兩個元素
所以s2的元素值就是:
s2[0] = 5
s2[1] = 6
s2[2] = 7
2)底層實現
如下圖所示slice內部三個元素
切片擴展有兩個規則:
1)slice可以向後擴展,不可以向前擴展
2)s[i]不可以超越len(s),向後擴展不可以超越底層數組cap(s)
package main
import "fmt"
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
fmt.Println(s1)
fmt.Println(len(s1))
fmt.Println(cap(s1))
s2 := s1[3:5]
fmt.Println(s2)
fmt.Println(len(s2))
fmt.Println(cap(s2))
}
輸出:
API server listening at: 127.0.0.1:21562
[2 3 4 5]
4
6
[5 6]
2
3
6.向切片增加元素
規則:
1)添加元素時如果超越cap,系統會重新分配更大的底層數組
2)由於值傳遞的關係,必須接收append的返回值(原因就是因爲可能超越cap,這時分配的是新的底層數組)
看下面一段代碼,通過append向切片內部增加元素
package main
import "fmt"
func main() {
arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
fmt.Println("s1 = ", s1)
s2 := s1[3:5]
fmt.Println("s2 = ", s2)
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
fmt.Println("s3, s4, s5 = ", s3, s4, s5)
fmt.Println("arr = ", arr)
}
輸出:
API server listening at: 127.0.0.1:18118
s1 = [2 3 4 5]
s2 = [5 6]
s3, s4, s5 = [5 6 10] [5 6 10 11] [5 6 10 11 12]
arr = [0 1 2 3 4 5 6 10]
上述代碼顯示s4和s5已經超越了arr所以這哥底層數組已經不是之前的arr了是一個新的arr
下面代碼通過打印len和cap觀察切片的長度和容量是如何擴展增加的,cap是倍數擴展的
package main
import "fmt"
func printSlice(s []int) {
fmt.Println("len(s) = cap(s) = ", len(s), cap(s))
}
func main() {
var s []int //沒有元素則切片是空的,不會崩潰
for i := 0; i < 10; i++ {
printSlice(s)
s = append(s, i)
}
fmt.Println(s)
}
輸出:
API server listening at: 127.0.0.1:25704
len(s) = cap(s) = 0 0
len(s) = cap(s) = 1 1
len(s) = cap(s) = 2 2
len(s) = cap(s) = 3 4
len(s) = cap(s) = 4 4
len(s) = cap(s) = 5 8
len(s) = cap(s) = 6 8
len(s) = cap(s) = 7 8
len(s) = cap(s) = 8 8
len(s) = cap(s) = 9 16
[0 1 2 3 4 5 6 7 8 9]
7.拷貝刪除操作
package main
import "fmt"
func main() {
s1 := []int{2, 4, 6, 8}
fmt.Println("s1 = ", s1)
s2 := make([]int, 16)
fmt.Println("s2 = ", s2)
copy(s2, s1) //拷貝s1到s2
fmt.Println("s2 = ", s2)
s2 = append(s2[:3], s2[4:]...) //刪除8
fmt.Println("s2 = ", s2) //打印出來可以看到8這個元素被刪除了整個切片的長度小了一個
//刪除頭元素操作
front := s2[0] //取出來查看頭元素
s2 = s2[1:] //刪除頭元素
fmt.Println("front = ", front)
fmt.Println("s2 = ", s2)
//刪除尾元素操作
tail := s2[len(s2)-1] //取出來查看尾元素
s2 = s2[:len(s2)-1] //刪除尾元素
fmt.Println("tail = ", tail)
fmt.Println("s2 = ", s2)
}
輸出:
API server listening at: 127.0.0.1:47314
s1 = [2 4 6 8]
s2 = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
s2 = [2 4 6 8 0 0 0 0 0 0 0 0 0 0 0 0]
s2 = [2 4 6 0 0 0 0 0 0 0 0 0 0 0 0]
front = 2
s2 = [4 6 0 0 0 0 0 0 0 0 0 0 0 0]
tail = 0
s2 = [4 6 0 0 0 0 0 0 0 0 0 0 0]