切片传参不加因[]t本身是轻量引用类型,仅复制24字节头信息;加反而引发逃逸、降低可读性;唯一例外是需修改len/cap本身。
切片传参为什么不用加 *?
因为 []T 本身就是轻量级引用类型:它只包含一个指针、一个长度和一个容量(共 24 字节),函数传参时只复制这三个字段,不拷贝底层数组。加 *[]T 反而多一层间接访问,还可能把切片头本身推到堆上(逃逸),得不偿失。
常见错误是看到“指针高效”就盲目套用:func process(s *[]byte) —— 这不仅没提速,还让调用方必须取地址(&buf),破坏了切片天然的可读性和安全性。
- ✅ 正确做法:直接传
[]byte,函数内用s = s[:n]或append修改内容(只要不扩容,就仍在原底层数组) - ❌ 错误信号:编译器提示
escape analysis显示切片头逃逸,或压测发现 cache miss 上升 - ⚠️ 唯一例外:你需要在函数内修改切片头三要素本身(比如想让调用方看到新的
len或cap改变),但这种情况极少,通常说明设计有误
[]MyStruct 和 []*MyStruct 性能差多少?
取决于结构体大小和操作频率。以一个含 7 个 string + 7 个 int64 的典型结构体为例,单个值约 168 字节;追加 100 万次,[]MyStruct 耗时约 3.5ms,[]*MyStruct 仅需 0.25ms —— 差 14 倍。
这不是“指针快”,而是避免了每次 append 都复制上百字节。但代价是:每个元素都是堆分配对象,GC 压力上升;且访问 s[i].Field 多一次内存跳转。