[]int 和 [3]int 类型不兼容、行为迥异、传参语义完全不同:前者是引用类型,仅拷贝24字节header;后者是值类型,传参会完整复制整个数组;[]int{1,2,3} 创建切片,[3]int{1,2,3}` 才创建数组。

Go 里 []int 和 [3]int 不是“差不多”,而是类型不兼容、行为迥异、传参语义完全不同的两种东西——混淆它们,轻则编译失败,重则数据被意外修改或内存泄漏。
赋值和函数传参时,[N]T 会整块复制,[]T 只拷贝 header
把一个 [1000]int 传给函数,Go 真的会复制 1000 个 int;而传 []int,只复制 24 字节(指针 + len + cap)。这不只是性能差异,更是语义鸿沟:
- 修改函数内接收到的
[N]T参数,不影响原数组(因为是副本) - 修改函数内接收到的
[]T元素(如s[0] = 1),可能改到调用方的底层数组 - 误把
arr := [3]int{1,2,3}当作切片传给期望[]int的函数 → 编译报错:cannot use arr (variable of type [3]int) as []int value
make 只支持 slice、map、chan,[N]T 无法用 make 创建
常见错误:写 make([5]int) 或 make([5]int, 0) —— 这根本不是合法语法,编译器直接拒绝。数组只能通过字面量或变量声明初始化:
-
arr := [3]int{1, 2, 3}✅ -
var arr [3]int✅(零值填充) -
arr := make([3]int)❌ 编译错误 -
sli := make([]int, 3)✅
反过来,[]int{1,2,3} 创建的是切片,不是数组;而 [3]int{1,2,3} 才是数组 —— 类型名里那个方括号位置和数字,就是类型系统里的铁律。
立即学习“go语言免费学习笔记(深入)”;
nil 切片 vs 零值数组:len 相同,但 == nil 行为天差地别
var s []int 是 nil 切片:len(s) == 0、cap(s) == 0、s == nil 为 true;var a [3]int 是零值数组:len(a) == 3、a == [3]int{0,0,0}、a == nil 编译不通过(数组不能和 nil 比较)。
- 对 nil 切片调用
append是安全的,Go 自动分配底层数组 - 对零值数组做
s := a[:]得到非 nil 切片,但若后续append超过容量,底层数组会被替换,原数组不受影响 - 用
if s == nil判断切片是否初始化,但永远不要对数组做这种判断
最易被忽略的点:切片的“引用性”不是语言层面的引用传递,而是结构体值传递 + 共享底层数组指针 —— 这意味着你得时刻意识到,s1 := s0[2:] 和 s2 := append(s0, x) 可能指向同一块内存,也可能在某次扩容后彻底分离。别靠猜,用 fmt.Printf("%p", &s[0]) 看地址,或用 reflect.ValueOf(s).UnsafeAddr() 验证共享关系。


















