[3]int 是指向数组的指针,[3]int 是含指针的数组;二者类型不同、内存布局不同、零值不同、解引用方式不同,不可互相赋值。

Go里 *[N]T 和 [N]*T 是两种完全不同的类型
它们不能互相赋值,编译器会直接报错。比如 var p *[3]int 和 var q [3]*int,哪怕长度和元素类型都一样,p = q 会触发 cannot use q (type [3]*int) as type *[3]int in assignment。
根本原因在于:前者是“指向一个含 3 个 int 的数组的指针”,后者是“一个含 3 个指向 int 的指针的数组”。内存布局、零值行为、解引用方式全都不一样。
-
*[3]int的零值是nil,解引用前必须确保它非 nil,否则 panic -
[3]*int的零值是[nil nil nil],每个元素默认为nil,访问q[0]不 panic,但*q[0]会 panic -
*[3]int可以用p[i]直接访问第 i 个元素(等价于(*p)[i]);而[3]*int必须写成*q[i]
传参时用 *[N]T 能避免数组值拷贝
Go 数组是值类型,传 [N]T 会复制全部 N 个元素。如果 N 很大(比如 [1024]byte),性能损耗明显。这时候用 *[N]T 传参,只传一个指针,开销固定为 8 字节(64 位系统)。
但要注意:函数内通过该指针修改数组内容,会影响原数组 —— 因为它指向的是原数组的内存地址。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 正确写法:
func process(arr *[1024]byte) { arr[0] = 1 } - 错误写法:
func process(arr [1024]byte) { ... }—— 白白拷贝 1KB - 别混淆:
func process(arr *[1024]byte)和func process(arr *[1024]byte)看起来一样,但如果你误写成func process(arr *[1024]*byte),类型就不匹配了
[N]*T 常用于动态管理多个独立对象地址
典型场景是缓存一组变量地址、保存多个结构体指针、或构建稀疏数据结构。例如:var ptrs [5]*string,你可以让其中某些元素指向真实字符串,其余保持 nil。
它不适用于需要连续内存块的操作(比如 memcpy 或 C 函数调用),因为这些指针指向的地址彼此无关,不一定相邻。
- 初始化常见写法:
ptrs := [3]*int{&x, &y, &z} - 单个元素可单独赋值:
ptrs[1] = &w - 遍历时要判空:
if ptrs[i] != nil { fmt.Println(*ptrs[i]) } - 别误写成
ptrs := []*int{&x, &y, &z}—— 这是切片,不是数组,长度不固定
调试时看打印输出能快速区分两者
Go 打印 *[N]T 和 [N]*T 的格式完全不同,这是最直观的区分手段。
-
fmt.Printf("%v", &arr)(arr [3]int)输出类似&[1 2 3] -
fmt.Printf("%v", ptrArr)(ptrArr *[3]int)也输出&[1 2 3]—— 它就是数组地址的表示 -
fmt.Printf("%v", ptrSlice)(ptrSlice [3]*int)输出类似[0xc000010230 0xc000010238 0xc000010240],即一串内存地址
真正容易被忽略的是:当你用 range 遍历 [N]*T 时,拿到的是指针副本,修改它本身(比如 ptr = &newVal)不影响原数组;但解引用后赋值(*ptr = newVal)才改原值。这个细节在逻辑复杂时极易出错。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










