Kind() == reflect.Ptr 是判断指针类型的唯一可靠方式,它对 nil 指针安全、不 panic,且不受层级嵌套或类型别名影响;Name() 和字符串匹配均不可靠。
Kind() 判断是否为指针类型最直接Go 没有语法层面的 isPointer 运算符,但 reflect.Kind() 是唯一可靠、轻量、不 panic 的判断依据。它返回的是底层类型“种类”,不是类型名,所以不会被 *int 和 **string 的表层写法干扰。
reflect.ValueOf(x).Kind() == reflect.Ptr → 是指针(包括 *T、**T 等任意层级)reflect.TypeOf(x).Kind() == reflect.Ptr → 同样有效,适合只关心类型定义的场景(比如参数校验)Kind() 对 nil 指针也安全,返回 reflect.Ptr,不会 panicvar p *int = nil v := reflect.ValueOf(p) fmt.Println(v.Kind() == reflect.Ptr) // true —— 安全
Name() 或字符串匹配来判断指针Name() 返回的是类型名(如 "int"),对指针类型永远返回空字符串;而把 Type.String() 结果拿去字符串匹配 "*",既脆弱又不可靠——结构体嵌套字段、泛型类型参数、别名类型都可能破坏匹配逻辑。
reflect.TypeOf(&x).Name() → ""(空),因为 *int 没有名字reflect.TypeOf(&x).String() → "*int",但 **map[string][]byte 这类就难解析type PtrInt *int),字符串匹配彻底失效Elem() 要配合 IsNil() 一起用想拿到指针指向的“真实类型”或“真实值”,必须调用 Elem(),但它在 nil 指针上会 panic。所以每次解引用前,必须确认非 nil 且可解引用。
v.Kind() == reflect.Ptr
!v.IsNil()(IsNil() 只对 Ptr、Slice、Map 等合法)v.Elem(),否则 panicfunc deref(v reflect.Value) reflect.Value {
for v.Kind() == reflect.Ptr {
if v.IsNil() {
return v // 或按需返回零值/错误
}
v = v.Elem()
}
return v
}
反射能改值的前提是:传入 reflect.ValueOf() 的是变量地址(&x),而不是值本身(x)。否则 SetXXX() 会 panic:“using unaddressable value”。
v := reflect.ValueOf(x); v.Elem().SetInt(42) → panicv := reflect.ValueOf(&x); v.Elem().SetInt(42) → 成功***int),只要最外层是可寻址的(即你传了 &p),就能一路 Elem().Elem().Elem() 改到底层
后续操作:解引用时忘了判 nil,改值时忘了传地址,或者误以为 Name() 能反映指针特征。记住,Kind() == reflect.Ptr 是唯一值得信赖的起点,其余全是围绕它做的防御性操作。