Go中数组长度是类型的一部分,编译期固化,[5]int与[6]int不兼容;[...]int是语法糖,实际生成固定大小数组;数组按值传递,大数组拷贝开销大;无append等动态操作,需用切片或指针替代。

数组长度是类型的一部分,不是运行时属性
Go 里 [5]int 和 [6]int 是两个完全不兼容的类型,编译器在类型检查阶段就拒绝赋值或传参。这不是“约定俗成”的限制,而是类型系统硬性要求。
- 函数参数写成
func f(a [5]int),传入[4]int或[]int都会报错:cannot use … (type [4]int) as type [5]int in argument to f - 即使两个数组内容、长度都一样,只要声明方式不同(比如一个用
[3]int{1,2,3},另一个用var a [3]int; a[0]=1; a[1]=2; a[2]=3),它们的类型也完全一致——关键只看[3]int这个字面量 - 多维数组同理:
[2][3]int和[3][2]int类型不同,不能互换
声明时省略长度([]T{…})只是语法糖,仍生成固定大小数组
写 a := []int{1,2,3} 看起来像切片,但编译器实际生成的是 [3]int 类型的值,然后隐式转为切片(如果上下文需要)。它不是“动态数组”,只是帮你省了数元素个数的麻烦。
- 这行代码等价于
a := [3]int{1,2,3};若你后续做b := a,b是完整复制的[3]int,不是共享底层内存 - 想确认真实类型?加一行
fmt.Printf("%T\n", a)—— 输出是[3]int,不是[]int - 若真要切片,得显式转换:
s := a[:],否则所有操作都按值传递,改s不影响a
数组按值传递,大数组拷贝开销明显
数组是值类型,函数调用、变量赋值都会复制整个内存块。对小数组(如 [4]byte)影响不大,但一旦超过缓存行大小(通常 64 字节),性能下降会立刻可见。
-
[1000]int在 64 位系统占 8000 字节,每次传参就是一次 8KB 内存拷贝 - 常见误写:
func process(data [1e6]float64) { ... }—— 建议改成func process(data *[1e6]float64)(传指针)或func process(data []float64)(传切片) - 用
unsafe.Sizeof测大小:fmt.Println(unsafe.Sizeof([100]int{}))能快速验证是否超出预期
连续内存布局带来局部性优势,但也限制扩容能力
数组元素在内存中严格连续排列,相邻元素地址差等于单个元素大小(如 int64 是 8 字节)。这对 CPU 缓存友好,但意味着无法像切片那样追加元素。
立即学习“go语言免费学习笔记(深入)”;
- 执行
&arr[0]和&arr地址相同,说明数组变量名直接指向首元素起始地址 - 没有
append、resize等操作——试图arr = append(arr, 42)会编译失败,因为append只接受切片 - 若需“固定结构 + 可变长度”,应封装为结构体:
type Header [4]byte+data []byte,而非强行用大数组预留空间
sizeof 那样可运行时查询,而是编译期就固化进类型签名里。这意味着任何依赖“动态确定数组长度”的逻辑,在 Go 里必须转向切片或反射,没法绕开。


















