不能直接转换,因切片[]t是值类型(含指针、len、cap三字段),*[]t是指向该头结构的指针,二者内存语义不同;需用unsafe.pointer重解释且确保布局一致。

Go 中指针和切片不能直接互转,但可通过 unsafe.Pointer 实现“类型重解释”——前提是内存布局一致且你清楚自己在做什么。
为什么不能直接把 *[]T 转成 []T 或反过来
切片 []T 是值类型(三元组:指针+长度+容量),而 *[]T 是指向该三元组的指针。两者语义完全不同:
-
[]T操作的是底层数组数据; -
*[]T操作的是切片头本身(比如想让函数修改切片的起始位置或长度)。
直接写 var s []int; p := &s; s2 := *p 是合法的,但这只是解引用,不是“转换”。真要绕过类型系统做底层 reinterpret(比如把 *MyStruct 当作 *[N]byte 用),必须走 unsafe。
用 unsafe.Pointer 把结构体指针转成字节切片(常见需求)
这是最常被问到的“指针转切片”场景:想把某个结构体实例按内存布局导出为 []byte,用于序列化或网络传输。
- 必须确保结构体没有指针字段(否则会触发 GC 问题);
- 必须用
unsafe.Sizeof算出实际占用字节数; - 不能对含
string、slice、map的结构体这么做,它们头部含指针。
示例:
type Header struct {
Magic uint32
Len uint16
}
h := Header{Magic: 0x12345678, Len: 100}
p := unsafe.Pointer(&h)
b := (*[unsafe.Sizeof(h)]byte)(p)[:]
// b 现在是长度为 6 的 []byte,内容即 h 的内存镜像
把 *[]T 当作 *T 处理?小心越界和对齐
有人想通过 *[]int 获取第一个元素地址,再当成 *int 用。这看似可行,但有硬限制:
- 切片非空(
len > 0),否则&(*s)[0]panic; - 必须用
unsafe.Slice(Go 1.21+)或老式(*[1 ; - 更安全的做法是直接用
(*s)[0]取值,或用&(*s)[0]得到*T,而非强行 reinterpret 指针类型。
错误示范:
// ❌ 错误:把 *[]int 当作 **int 解释,内存布局不匹配 p := (*int)(unsafe.Pointer(&s)) // s 是 []int,&s 是 *[]int,不是 **int
切片头指针操作:*[]T 的真实用途
*[]T 唯一正当用途是让函数能修改调用方的切片头(比如重置、截断、扩容后回写):
- 函数内必须显式
*s = append(*s, x)或*s = (*s)[i:j]; - 不加
*赋值只改局部副本; - 不要试图把
*[]T强转成其他指针类型——它只是个指向 slice header 的指针,header 结构是 runtime 内部约定,不应依赖。
典型模式:
func truncate(s *[]int, n int) {
if n
<p>真正难的不是语法,而是判断:你到底需要共享底层数组(用切片本身),还是需要修改切片头(用 <code>*[]T</code>),抑或必须穿透类型系统读写内存(此时才轮到 <code>unsafe.Pointer</code>)。三者目的不同,混用必出错。</p>golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











