3.1 数组和切片
peter 164 3

数组的声明

var a [3]int // 声明初始化为默认零 值
a[0] = 1
b := [3]int{1, 2, 3}           // 声明同时初始化
c := [2][2]int{{1, 2}, {3, 4}} // 多维数组初始化

测试实例 1

func TestArrayInit(t *testing.T)  {
    var arr[3]int
    arr1 := [4]int{1,2,3,4}
    arr2 := [...]int{1,2,3}
     t.Log(arr[0], arr[1], arr[2])
    t.Log(arr1[1])
    t.Log(arr2[1])
}

数组元素遍历

与其他主要编程语言的差异

通过代码实例了解一下

测试实例 2

// 数组遍历
func TestArrayTravel(t *testing.T)  {
    arr := [...]int{1,2,3}
    for i:= 0; i < len(arr); i++ {
        t.Log(arr[i])
    }

    // Go 语言写法,类似于 java 中的 for each 写法
    for idx, e := range arr {
        t.Log(idx, e)
    }

    // 如果不关心 idx,那么将对应位置置为 _
    for _, e := range arr {
        t.Log(e)
    }
}

数组截取

a[开始索引(包含),结束索引(不包含)]

func TestTruncatedArray(t *testing.T) {
    a := [...]int{1, 2, 3, 4, 5}
    t.Log(a[1:2])  // [2]
    t.Log(a[1:3])  // [2 3]
    t.Log(a[1:len(a)])  // [2 3 4 5]
    t.Log(a[1:])  // [2 3 4 5]
    t.Log(a[:3])  // [1 2 3]
}

切片内部结构

切片内部结构是一个结构体

  • ptr 指针,指向一个连续存储空间
  • len 元素的个数,可以访问的元素的个数
  • cap 内部数组的容量
image-20210109163218953

通过代码实例 3 感受一下 lencap 的区别

package slice_test

import "testing"

func TestSliceInit(t *testing.T) {
    // 声明一个 slice,并不需要指定数组的长度
    var s0 []int
    t.Log(len(s0), cap(s0)) // 0 0

    s0 = append(s0, 1)
    t.Log(len(s0), cap(s0)) // 1 1

    s1 := []int{1, 2, 3, 4}
    t.Log(len(s1), cap(s1)) // 4 4

    s2:=make([]int, 3, 5)
    t.Log(len(s2), cap(s2))
    t.Log(s2[0], s2[1], s2[2])  // 0 0 0
    //t.Log(s2[3], s2[4])  // panic: runtime error: index out of range [3] with length 3
    s2 = append(s2, 9)
    t.Log(len(s2), cap(s2))  // 4 5
    t.Log(s2[3])  // 9
}

切片共享存储结构

在介绍这之前,我们先来了解一下 cap 的增长过程,参见实例代码 3

测试实例 3

func TestSliceGrowing(t *testing.T) {
   s := []int{}
   for i := 0; i < 10; i++ {
      s = append(s, i)
      t.Log(len(s), cap(s))
   }
}

运行结果

image-20210109164400159

从代码的运行结果可以看出:cap 会在放入的元素个数已经超出原有的 cap 容量时,cap 的值会增长,并且每一次 cap 的增长都是前一次的 2 倍。不过每一次增长,slice 都会开辟一个新的连续内存空间,并将原有的值复制过去。

接下来,我们介绍 slice 的共享存储结构

测试实例 4

func TestSliceShareMemory(t *testing.T) {
    months := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}

    Q2 := months[3:6]
    t.Log(Q2)               // [Apr May Jun]
    t.Log(len(Q2), cap(Q2)) // 3 9

    summer := months[5:8]
    t.Log(summer)                   // [Jun Jul Aug]
    t.Log(len(summer), cap(summer)) // 3 7

    // 共享数组的修改会影响到所有人
    summer[0] = "Unknown"
    t.Log(Q2) // [Apr May Unknown]
}
image-20210109164202283

数组 vs. 切片

  1. 容量是否可伸缩
  2. 是否可以进行比较

测试实例 5

func TestSliceCompare(t *testing.T) {
    a := []int{1, 2, 3, 4}
    b := []int{1, 2, 3, 4}

    // invalid operation: a == b (slice can only be compared to nil)
    if a == b {
        t.Log("equal")
    }
}

代码实例 5 说明:slice 是不可以比较的,或者说只可以和 nil 进行比较

预览图
评论区

索引目录