go中声明指向数组的指针必须显式指定长度,如[3]int,不能用[]int(语法错误);因数组长度是类型组成部分,&arr的类型自动推导为*[n]t。

Go 中声明指向数组的指针必须显式写出数组长度
Go 不允许用 []int 这类切片类型来声明指向数组的指针——那会编译失败。真正能被取地址的数组类型是带长度的,比如 [3]int、[100]byte。所以指针类型必须完整写成 *[3]int,而不是 *[]int(后者语法错误)。
常见错误现象:cannot use &arr as *[]int value in assignment,本质是混淆了数组和切片类型。
-
arr := [3]int{1, 2, 3}→ptr := &arr的类型自动推导为*[3]int - 若想显式声明变量,得写
var ptr *[3]int = &arr,不能省略3 - 长度是类型的一部分:
为什么不能用 *[]int 声明指向数组的指针
[]int 是切片类型,它本身是三字段结构体(data ptr + len + cap),不是数组。对一个数组取地址得到的是指向连续内存块的指针,而 *[]int 表示“指向一个切片变量的指针”,语义完全不同。
典型误用场景:想把数组传给函数并修改原数组内容,却错误声明为 func f(p *[]int),结果发现改不了、甚至编译不过。
- 正确做法是接收
*[N]T,例如func f(p *[3]int) - 若传切片,函数签名应为
func f(s []int),此时 s 是副本,但底层 data 指针共享,可修改元素 -
*[]int只在极少数需要修改切片头(比如重分配整个切片变量)时才用,和数组无关
数组指针作为函数参数的实际写法
当需要函数内直接修改原数组(而非仅改元素),且数组大小固定,用数组指针最清晰。注意:传参时仍要保证长度匹配。
func zeroArr(p *[4]int) {
for i := range p {
(*p)[i] = 0 // 解引用后操作
}
}
arr := [4]int{1, 2, 3, 4}
zeroArr(&arr) // OK
// zeroArr(&[3]int{1,2,3}) // 编译错误:类型不匹配
- 函数体内必须先解引用
*p才能当数组用,不能直接对p做索引(p[i]非法) - 如果数组长度是变量(比如由配置决定),无法用数组指针;此时只能用切片或 unsafe(不推荐)
- 性能上,
*[N]T传参只传 8 字节指针,比传整个大数组高效,也比切片多一层间接访问
容易忽略的兼容性细节:数组指针和切片不能混用
即使底层数据相同,*[5]int 和 []int 之间没有隐式转换。试图把 &arr 直接赋给 []int 类型变量会报错。
- 从数组指针转切片需手动转换:
s := (*p)[:]或s := p[:](Go 1.17+ 支持后者简写) - 反过来,从切片获取数组指针几乎不可能——除非已知底层数组长度且用
unsafe,风险极高 - JSON 解码到数组指针字段时,标准库会拒绝(因为
*[N]T不实现Unmarshaler),需中间变量或自定义解码逻辑
*[N]T,N 就锁死了,没法泛化,这是和 C 最不一样的地方。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











