切片

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]

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章