go中[3]int不能传给[]int函数,因二者是完全不同的类型,编译器不隐式转换;数组传参复制整块内存,切片仅传24字节头信息;小数组可值传,大数组应传指针或转切片。

Go 语言里没有“Array 函数”这种内置类型或概念,array 是值类型,不能直接当函数用;你真正要处理的,是「如何把数组传给函数」以及「该用 [N]T 还是 []T」——选错会导致编译失败、性能浪费或逻辑错误。
为什么 [3]int 不能直接传给接收 []int 的函数
这是最常卡住人的编译错误:cannot use a (type [3]int) as type []int in argument to nameReader。根本原因是:Go 中 [3]int 和 []int 是**完全不同的类型**,编译器不做隐式转换。
-
[3]int表示“长度为 3 的整数数组”,类型名里就含长度 -
[]int是切片,底层包含指针+长度+容量,和数组类型不兼容 - 即使你写
nameReader(a[:]),也是显式转成切片,不是“自动适配”
[N]T 作为参数:只适合小而固定、无需修改原数组的场景
声明形参为 func f(arr [5]int) 意味着:调用方必须传一个长度恰好为 5 的数组,且函数内所有操作都基于这个确定长度。它适合做校验、解包、纯计算等轻量任务。
- 优点:编译期长度检查,避免运行时越界(比如处理 RGB 像素
[3]uint8) - 缺点:无法接收
[4]int或[6]int,也不能接收切片;大数组传参会复制整块内存 - 常见误用:拿
var x [1000]int直接传给func process([1000]int)—— 每次调用都拷贝 1000 个 int,开销明显
[]T 作为参数:绝大多数情况该选它
几乎所有标准库函数(sort.Ints、strings.Join、json.Marshal)都用切片签名,因为灵活、零拷贝(只复制头信息)、支持任意长度。
- 传数组过去?用切片语法:
f(myArray[:])或f(myArray[0:5]) - 想在函数里改原数组元素?可以,只要没触发
append扩容(扩容后底层数组可能换掉) - 想安全地增删元素并让调用方看到变化?必须返回新切片:
return append(s, x),然后调用方重新赋值 - 注意边界:
len(s)是当前长度,cap(s)是底层数组剩余空间,别假设cap == len
需要修改原数组内容?优先传指针 *[N]T,而不是盲目用切片
当你明确知道数组长度固定、又必须原地修改(比如硬件寄存器映射、固定帧头结构),传指针比切片更语义清晰、无歧义。
- 声明:
func resetHeader(hdr *[4]byte) - 调用:
resetHeader(&myHeader)—— 明确表示“我要动你本体” - 对比切片:
hdr[:] = [...]byte{0,0,0,0}看似等价,但若hdr是从更大底层数组切出来的,就可能意外改到其他数据 - 性能:指针传参只压栈 8 字节,无论数组多大;切片传参也快,但语义不如指针精准
最容易被忽略的一点:数组长度是类型的一部分,所以 [1024]byte 和 [2048]byte 之间连类型断言都过不了。如果你在封装协议解析、序列化工具,别试图用泛型约束数组长度——直接用切片 + 显式长度检查更实际。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











