数组是由相同类型元素的集合组成的数据结构,计算机会为数组分配一块连续的内存来保存其中的元素

Go 语言数组在初始化之后大小就无法改变

类型

元素类型 Elem 和数组的大小 Bound,这两个字段共同构成了数组类型
存储元素类型相同、但是大小不同的数组类型在 Go 语言看来也是完全不同

初始化

  1. arr1 := [3]int{1, 2, 3}
  2. arr2 := [...]int{1, 2, 3}

优化

  1. 当元素数量小于或者等于 4 个时,会直接将数组中的元素放置在栈上;
  2. 当元素数量大于 4 个时,会将数组中的元素放置到静态区并在运行时取出;

语句转换(关键字:4)
假设代码需要初始化 [3]int{1, 2, 3} ,那么我们可以将上述过程理解成以下的伪代码:

  1. var arr [3]int
  2. arr[0] = 1
  3. arr[1] = 2
  4. arr[2] = 3

假设代码需要初始化 [5]int{1, 2, 3, 4, 5},那么我们可以将上述过程理解成以下的伪代码:

  1. var arr [5]int
  2. statictmp_0[0] = 1
  3. statictmp_0[1] = 2
  4. statictmp_0[2] = 3
  5. statictmp_0[3] = 4
  6. statictmp_0[4] = 5
  7. arr = statictmp_0

总结起来,在不考虑逃逸分析的情况下,如果数组中元素的个数小于或者等于 4 个,那么所有的变量会直接在栈上初始化,如果数组元素大于 4 个,变量就会在静态存储区初始化然后拷贝到栈上

访问

无论是在栈上还是静态存储区,数组在内存中都是一连串的内存空间,我们通过指向数组开头的指针、元素的数量以及元素类型占的空间大小表示数组。

  • 如果我们不知道数组中元素的数量,访问时可能发生越界;
  • 而如果不知道数组中元素类型的大小,就没有办法知道应该一次取出多少字节的数据,

无论丢失了哪个信息,我们都无法知道这片连续的内存空间到底存储了什么数据:

Go 语言对于数组的访问还是有着比较多的检查的,它不仅会在编译期间提前发现一些简单的越界错误并插入用于检测数组上限的函数调用,还会在运行期间通过插入的函数保证不会发生越界。

总结

数组的类型由长度和元素共同决定
数组存储于一块连续内存上
数组的重要信息是 开始指针、元素个数以及元素大小
数组的初始化方式以及位置和数组元素个数有关

相关

静态存储区、堆和栈的区别
image.png