用 reflect.kind 区分指针和普通类型需调用 type.kind() 或 value.kind():ptr 表示指针类型,int、string 等表示普通类型;注意 nil 指针需先检查 isnil() 再 elem(),且 go 无引用类型,故无 ref kind。

怎么用 reflect.Kind 区分指针和普通类型
Go 的反射中,reflect.Kind 是底层类型分类,不是你声明的类型名。比如 *int 的 Kind 是 Ptr,而 int 是 Int;但 []int 的 Kind 是 Slice,不是 Array —— 这点容易误判。
关键在于:别看 reflect.Type.String()(它返回 "*int"),要看 reflect.Type.Kind() 返回的枚举值。
-
reflect.TypeOf((*int)(nil)).Elem().Kind() == reflect.Int:先取指针的元素类型,再看它的 kind -
reflect.TypeOf(&struct{}{}).Kind() == reflect.Ptr:直接对指针变量调用,kind 就是Ptr - 如果传入
nil接口值,reflect.ValueOf(nil)会 panic,得先用reflect.Value.IsValid()检查
reflect.Value.Kind() 和 reflect.Type.Kind() 有什么区别
两者返回值一样,但来源不同:Type.Kind() 描述类型的静态分类(编译期确定),Value.Kind() 描述当前值的底层类型分类(运行时有效)。大多数时候用哪个都行,但注意边界:
- 对未初始化的接口变量(如
var v interface{}),reflect.ValueOf(v).Kind()是Invalid,不能直接取.Kind() -
reflect.TypeOf(v).Kind()在v是nil接口时仍能返回其类型 kind(比如Interface),但前提是该接口有具体类型信息 - 结构体字段反射时,
field.Type.Kind()看字段声明类型,field.Value.Kind()看当前值的实际 kind(可能为Invalid)
判断是否为“可解引用的指针”要多走一步
仅靠 Kind() == reflect.Ptr 不够:它只说明是指针类型,但不保证能安全 .Elem()。比如 var p *int 为 nil 时,reflect.ValueOf(p).Elem() 会 panic。
立即学习“go语言免费学习笔记(深入)”;
- 先确认
v.Kind() == reflect.Ptr - 再检查
v.IsNil() == false,否则.Elem()不合法 - 如果目标是“非 nil 指针且指向有效值”,这两步缺一不可
- 常见错误:在 JSON 反序列化后直接对字段做
.Elem(),没意识到字段可能仍是nil
为什么 reflect.Kind 里没有 “reference” 这个概念
Go 语言没有 C++ 那种引用类型(&T 不是独立类型),所有“引用语义”都通过指针、切片、map、channel、func 等内置引用类型实现。所以 reflect.Kind 枚举里压根没有 Ref 或类似值。
-
slice、map、chan、func、ptr这五种 kind 在运行时都持有底层数据的引用,但它们的Kind各不相同 - 想统一识别“可能修改原值”的类型?只能手动列:
v.Kind() == reflect.Ptr || v.Kind() == reflect.Slice || v.Kind() == reflect.Map || ... - 别试图用
reflect.Kind判断“是否引用传递”——Go 的参数传递永远是值传递,只是某些值本身包含指针
真正难的不是写对 Kind 判断,而是想清楚你到底要捕获哪一类行为:是类型构造(*T),还是运行时可变性(len(s) > 0),还是内存共享(unsafe.Pointer 场景)。这三者在反射里得用不同组合来逼近。










