只有导出方法才能被reflect获取,非导出方法在reflect.type中根本不存在;值类型反射仅见值接收者方法,指针类型可见全部导出方法;methodbyname查不到返回零值,调用前须确保接收者匹配且参数类型数量严格一致。

用 reflect.TypeOf 获取结构体类型再调用 NumMethod 和 Method
Go 的反射中,只有导出(首字母大写)方法才能被 reflect 获取到。非导出方法在 reflect.Type 中完全不可见,不是“获取不到”,而是根本不存在于方法集里。
正确路径是:先用 reflect.TypeOf 拿到类型对象(注意传指针或值本身会影响方法集——接口实现和接收者类型有关),再遍历方法:
type User struct{ Name string }
func (u User) GetName() string { return u.Name }
func (u *User) SetName(n string) { u.Name = n }
u := User{}
t := reflect.TypeOf(u) // 值类型,只能看到值接收者方法
fmt.Println(t.NumMethod()) // 输出 1(只有 GetName)
t2 := reflect.TypeOf(&u) // 指针类型,能看到值+指针接收者方法
fmt.Println(t2.NumMethod()) // 输出 2(GetName + SetName)
区分 Method 和 MethodByName:一个遍历,一个查单个
Method(i) 按索引取方法,返回 reflect.Method,含名称、类型、函数值;MethodByName(name) 直接查,查不到返回零值(reflect.Value{}),不报错。
- 遍历所有方法时用
Method(i),配合NumMethod() - 明确知道方法名且只调一个,用
MethodByName更简洁 - 注意:方法名必须完全匹配,大小写敏感,且必须导出
-
MethodByName返回的是reflect.Value,不是reflect.Method,不能直接读元信息(如参数列表),要读得用Method配合Type().In(i)
调用前必须检查接收者类型是否匹配
反射调用方法本质是调用函数值,但 Go 对接收者有严格约束:值接收者方法不能在指针实例上调用(除非自动取地址),指针接收者方法不能在纯值上直接调(会 panic)。
立即学习“go语言免费学习笔记(深入)”;
常见 panic:reflect: Call using zero Value argument 或 reflect: Call of method on zero Value,多数是因为 reflect.Value 是零值,或接收者不匹配。
- 用
reflect.ValueOf(x)获取实例时,确保x非 nil(尤其指针) - 调用指针接收者方法,必须传
reflect.ValueOf(&x),而不是reflect.ValueOf(x) - 调用前可用
v.CanAddr()和v.Kind() == reflect.Ptr判断是否可安全取地址 - 稳妥做法:统一用指针传入,再用
v.Elem()处理值接收者(如果需要)
实际调用要处理参数和返回值的 reflect.Value 转换
反射调用不是直接传 Go 原生参数,所有参数都得是 reflect.Value 切片,返回值也是 reflect.Value 切片。没转换好就会 panic 或静默失败。
- 参数必须数量、类型完全匹配方法签名,不能自动转换(比如
int不能当int64) - 用
reflect.ValueOf(arg).Convert(targetType)强转前,先确认arg类型是否可转换(CanConvert) - 返回值切片长度取决于方法声明的返回值个数,哪怕返回
error也要显式接收 - 若方法返回多值,别漏掉
rets[0].Interface()之后的rets[1].Interface()
最易忽略的一点:结构体字段未导出时,其所在方法即使导出,也可能因内部访问字段而运行时报错(比如方法里读了私有字段但调用方无权访问),这不是反射问题,是 Go 的可见性规则在运行时生效。










