数组 array
是相同类型元素组成的集合
初始化后大小无法改变
对于数组类型 必须满足 存储元素类型相同 且 大小相同 才被认为同一类型元素
-
结构
/go1.15/src/cmd/compile/internal/types/type.go// Array contains Type fields specific to array types. type Array struct { Elem *Type // element type Bound int64 // number of elements; <0 if unknown yet } -
上限推导
arr1 := [3]int{1,2,3} arr2 := [...]int{1,2,3}- 对于未给定数目的数组,调用
go1.15/src/cmd/compile/internal/gc/typecheck.gotypecheckarraylit() 通过 遍历 方式计算数量- [...] 初始化方式只是一种语法糖,两种方式完全等价
- 对于未给定数目的数组,调用
-
语句转换
优化:
go1.15/src/cmd/compile/internal/gc/sinit.goanylit()->fixedlit()-
当元素 小于等于
4个,会直接将数组的元素放置在栈上 initKindDynamicvar arr [3]int arr[0] = 1 arr[1] = 2 arr[3] = 3 -
当元素 大于
4个,会将数组元素放到静态区并在运行时取出 initKindStaticvar arr [5]int //调用 staticname() 获取唯一的staticname statictmp_0 statictmp_0[0] = 1 statictmp_0[1] = 2 statictmp_0[2] = 3 statictmp_0[3] = 4 statictmp_0[4] = 5 arr = statictmp_0 -
优化理解:
- 静态存储区是编译就分配好的空间,在数组数量多的情况下,提前放在静态区减少数组初始化时间,提高性能。
-
访问和赋值
- 编译期间的SSA
/go1.15/src/cmd/compile/internal/gc/typecheck.gotypecheck1()- 检查访问数组索引 是否非法 非整数 || 负数 || 越界 -> 只针对字面量可以判断是否合法
- 运行时检查 panicIndex -> goPanicIndex
- 当编译时无法判断是否越界时,SSA生成 IsInBounds 越界检查指令,若越界,触发 PanicBounds 指令执行
runtime.panicIndex - 判断后 分别走访问 和 赋值指令
- 当编译时无法判断是否越界时,SSA生成 IsInBounds 越界检查指令,若越界,触发 PanicBounds 指令执行
- 理解:
- 字面量访问下标:无论是数组的寻址还是赋值,都是在编译阶段完成的,没有运行时的参与
- 无法判断数组下标时:会加入 PanicBounds 指令交给运行时进行判断
- 编译期间的SSA