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