Go反射调用结构体数组元素MethodByName触发zero Value panic如何解决
问题原因分析
- 你的
FullName()方法是定义在*EsEntry指针接收者上的,只有拿到结构体实例的指针,才能调用该方法 - 原代码中
item是reflect.Value类型的变量,reflect.ValueOf(&item)取的是reflect.Value变量本身的内存地址,完全不是你要的EsEntry结构体的指针,自然找不到FullName方法,返回零值后调用Call就触发了panic。
修复方案
把错误的获取指针逻辑替换成用反射自带的Addr()方法拿到结构体的指针,同时建议增加方法有效性判断避免panic,修复后代码如下:
package main import ( "fmt" "reflect" ) type EsEntry struct { Wholename string } var EsPersonList []EsEntry func (this *EsEntry) FullName() string { return this.Wholename } func createStr(d interface{}) { items := reflect.ValueOf(d) if items.Kind() == reflect.Slice { for i := 0; i < items.Len(); i++ { item := items.Index(i) if item.Kind() == reflect.Struct { // 用Addr()拿到结构体实例的指针,对应*EsEntry类型 v := item.Addr() // 先判断方法是否存在,避免panic method := v.MethodByName("FullName") if !method.IsValid() { continue } return_values := method.Call([]reflect.Value{}) fmt.Println(return_values) } } } } func main() { // 测试数据 EsPersonList = append(EsPersonList, EsEntry{Wholename: "张三"}, EsEntry{Wholename: "李四"}) createStr(EsPersonList) }
补充说明
- 如果你切片存储的本身就是
[]*EsEntry类型,那不需要调用Addr(),直接对item调用MethodByName即可找到方法。 - 反射调用方法前建议先判断
reflect.Value的IsValid()返回值,可以有效避免这类空调用panic。
内容的提问来源于stack exchange,提问作者VLK
相关产品推荐
相关产品推荐

