在 Go 中,用 reflect.Indirect 配合 reflect.ValueOf 可安全获取指针指向的实际类型,它递归解引用多级指针或接口,返回非指针非接口的 reflect.Value,再调用 .Type() 得到底层类型;对非指针值原样返回,nil 指针返回无效 Value 需检查。

在 Go 中,获取指针指向的**实际类型**(而非指针类型本身),常用 reflect.Indirect 配合 reflect.TypeOf 或 reflect.ValueOf。关键在于:指针可能多层嵌套(如 **int),Indirect 会递归解引用直到得到非指针值,返回其 reflect.Type 或 reflect.Value。
用 reflect.Indirect 获取指针指向的 Type
reflect.Indirect 接收一个 reflect.Value,若该值是接口或指针类型,它会持续解引用,直到得到一个非指针、非接口的值(或 nil)。之后可调用 .Type() 得到最终类型。
- 直接对指针变量调用
reflect.TypeOf(v)返回的是*T类型;要得到T,需先转为Value再Indirect -
reflect.Indirect对非指针值(如 int、struct 值)会原样返回,安全可用 - 若传入 nil 指针,
Indirect返回零值reflect.Value(.IsValid() == false),需检查
典型用法示例
以下代码演示如何从任意指针(包括多级)安全提取底层类型名:
func getUnderlyingType(v interface{}) string {
val := reflect.ValueOf(v)
if !val.IsValid() {
return "invalid"
}
indirectVal := reflect.Indirect(val)
if !indirectVal.IsValid() {
return "nil pointer"
}
return indirectVal.Type().String()
}
// 使用
var i int = 42
p := &i
pp := &p
fmt.Println(getUnderlyingType(p)) // "int"
fmt.Println(getUnderlyingType(pp)) // "int"
fmt.Println(getUnderlyingType(42)) // "int"(非指针也兼容)
与 reflect.TypeOf 的区别和配合
reflect.TypeOf 只做静态类型检查,不处理运行时解引用;reflect.Indirect 是运行时操作,依赖 reflect.Value。
立即学习“go语言免费学习笔记(深入)”;
-
reflect.TypeOf(&i)→*int -
reflect.Indirect(reflect.ValueOf(&i)).Type()→int - 若想同时支持值和指针输入,统一用
reflect.ValueOf(x)后接Indirect最稳妥
注意事项与常见坑
实际使用中容易忽略这些细节:
-
Indirect不改变原始变量,只返回新Value;如需修改原指针指向的值,要用.Addr().Interface()或.Set*方法 - 对未导出字段的结构体指针,
Indirect能拿到类型,但无法读写字段(反射权限限制) - 接口类型(
interface{})传入后,ValueOf得到的是接口内部存储的值,Indirect会对其内部值解引用(如果它是指针)










