因为数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性。 例如:

func arraySum(x [3]int) int{
    sum := 0
    for _, v := range x{
        sum = sum + v
    }
    return sum
}

这个求和函数只能接受[3]int类型,其他的都不支持。 再比如,

a := [3]int{1, 2, 3}

数组a中已经有三个元素了,我们不能再继续往数组a中添加新元素了。

切片

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。

切片是一个引用类型,它的内部结构包含地址长度容量。切片一般用于快速地操作一块数据集合。

值类型与引用型的区别:

Go语言 - 切片

底层数组的修改会影响切片
切片的修改也会影响底层数组

 切片的定义

var name []T
// 切片拥有数组的所有特性
  • name:表示变量名
  • T:表示切片中的元素类型

切片的声明

package main

import "fmt"

func main()  {
    // 切片声明方式一  直接声明
    var s = []int{1,2,3}
    fmt.Println(s)  // [1 2 3]
    fmt.Printf("%T \n", s)  // []int

    // 切片声明方式二 从数组中得到切片
    var a = [3]int{1,2,3}
    c := a[0:3]
    fmt.Println(c)  // [1 2 3]
    fmt.Printf("%T \n", c)  // []int

}

切片的长度和容量

切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。

package main

import "fmt"

func main()  {
    var a1 = [...]string{"北京", "上海", "深圳", "成都", "广州", "青岛"}
    s1 := a1[1:4]
    // 切片的大小 (切片内目前元素的数量)
    fmt.Println(len(s1))  // 3
    // 切片的容量 (底层数组最大能放多少元素)
    fmt.Println(cap(s1))  // 5  

}

切片的本质

切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。

举个例子,现在有一个数组a := [8]int{0, 1, 2, 3, 4, 5, 6, 7},切片s1 := a[:5],相应示意图如下。Go语言 - 切片切片s2 := a[3:6],相应示意图如下:Go语言 - 切片

append()方法为切片添加元素

Go语言的内建函数append()可以为切片动态添加元素。 每个切片会指向一个底层数组,这个数组能容纳一定数量的元素。当底层数组不能容纳新增的元素时,切片就会自动按照一定的策略进行“扩容”,此时该切片指向的底层数组就会更换。“扩容”操作往往发生在append()函数调用时。 举个例子:

func main() {
    //append()添加元素和切片扩容
    var numSlice []int
    for i := 0; i < 10; i++ {
        numSlice = append(numSlice, i)
        fmt.Printf("%v  len:%d  cap:%d  ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)
    }
}

 

[0]  len:1  cap:1  ptr:0xc0000a8000
[0 1]  len:2  cap:2  ptr:0xc0000a8040
[0 1 2]  len:3  cap:4  ptr:0xc0000b2020
[0 1 2 3]  len:4  cap:4  ptr:0xc0000b2020
[0 1 2 3 4]  len:5  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5]  len:6  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6]  len:7  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6 7]  len:8  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6 7 8]  len:9  cap:16  ptr:0xc0000b8000
[0 1 2 3 4 5 6 7 8 9]  len:10  cap:16  ptr:0xc0000b8000

append()函数将元素追加到切片的最后并返回该切片。

切片numSlice的容量按照1,2,4,8,16这样的规则自动进行扩容,每次扩容后都是扩容前的2倍

切片的扩容策略

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
    newcap = cap
} else {
    if old.len < 1024 {
        newcap = doublecap
    } else {
        // Check 0 < newcap to detect overflow
        // and prevent an infinite loop.
        for 0 < newcap && newcap < cap {
            newcap += newcap / 4
        }
        // Set newcap to the requested cap when
        // the newcap calculation overflowed.
        if newcap <= 0 {
            newcap = cap
        }
    }
}
源码

相关文章:

  • 2021-07-06
  • 2021-08-22
  • 2021-05-13
  • 2021-11-03
  • 2022-12-23
  • 2022-12-23
  • 2021-10-03
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-11
  • 2021-10-09
相关资源
相似解决方案