go中[3]int是固定长度数组,[]int是切片;数组长度是类型一部分,不同长度不可互赋;初始化时未显式赋值的元素自动为零值,复合字面量支持索引指定和部分赋值。

Go 语言里写 [3]int 和 []int 看起来只差一对方括号,但语义完全不同:前者是固定长度的数组类型,后者是切片(slice)——而绝大多数人实际想要的、能直接传参/扩容/赋值的,其实是后者。真要用数组,必须清楚它不可变、会整块拷贝、不同长度就是不同类型。
声明时指定长度并留空,所有元素自动为零值
这是最基础也最容易被忽略“初始化”含义的方式。所谓“初始化”,不一定要显式赋值;只要声明完成,内存就已分配,每个元素按类型填入零值。
-
var a [5]int→ 全是0,不是未定义 -
var s [3]string→ 全是"" -
var b [2]*int→ 全是nil
这种写法适合后续用循环或单个索引逐步赋值,比如读取固定长度的二进制头信息、预分配缓冲区等场景。注意:此时不能用 len(a) 以外的方式获取长度——数组长度是类型的一部分,cap(a) 会报错。
用复合字面量初始化,支持部分赋值和索引指定
Go 允许在初始化时只给前几个元素赋值,其余保持零值;也能跳着指定下标,编译器自动推导总长度。
-
a := [5]int{1, 2}→ 等价于[5]int{1, 2, 0, 0, 0} -
b := [5]int{1: 10, 3: 30}→ 等价于[5]int{0, 10, 0, 30, 0} -
c := [5]int{0: 100, 4: 500}→ 首尾指定,中间全零
关键点:一旦用了索引(如 1:),就必须带冒号;没带冒号的值默认按顺序填到下一个空位;最大索引决定数组长度,哪怕中间全是零值。容易踩坑的是误以为 [5]int{1:10} 是“只初始化第二个”,其实它生成的是长度为 5 的数组,不是长度为 2。
用 []T{...} 写法时,你得到的不是数组而是切片
这是最常被误解的一点。写 arr := []int{1, 2, 3},arr 的类型是 []int(切片),不是 [3]int(数组)。它底层指向一个匿名数组,但行为完全由切片规则控制:可追加、可传递、不会整块拷贝。
- 想传给只接受
[3]int的函数?不行,类型不匹配 - 想取地址传给
*[3]int?可以,但得显式转换:&[3]int{1,2,3} - 想确认是不是数组?用
fmt.Printf("%T", arr)看输出
真正需要数组的场合极少,比如 CGO 交互、内存对齐要求严格的结构体字段、或实现某些底层协议头。日常开发中,95% 的情况该用切片。
二维数组初始化必须用嵌套大括号,且每行末尾要逗号
二维数组本质是“数组的数组”,初始化语法严格。漏掉逗号或括号层级错,编译直接失败。
matrix := [2][3]int{
{1, 2, 3}, // 这行末尾必须有逗号
{4, 5, 6}, // 同样
}
如果只初始化部分行或列:
-
[2][3]int{{1}, {4, 5}}→ 第一行是[3]int{1, 0, 0},第二行是[3]int{4, 5, 0} -
[2][3]int{1: {4, 5}}→ 第一行全零,第二行前两个为 4、5,第三个为 0
别试图用 [][]int 初始化二维数组——那是个切片的切片,和二维数组内存布局、类型兼容性都不同。需要固定行列时,必须用 [N][M]T 形式。
数组真正的复杂点不在语法,而在它的“类型即长度”特性:两个数组变量即使元素类型和值完全一样,只要长度不同,就不能互相赋值、不能作为同一函数参数传入、甚至无法用同一个接口接收。这点在泛型约束或反射操作时会突然暴露出来,而且错误信息往往不提示“长度不匹配”,只说“类型不一致”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











