Go反射如何获取结构体字段_Go结构体反射读取方法

用reflect.ValueOf获取结构体值后需调用.Elem()解引用指针,再通过.NumField()和.Field(i)遍历字段值,字段名须用.Type().Field(i).Name获取。

Go反射怎么拿到结构体字段名和值

reflect.ValueOf 获取结构体的 reflect.Value,再调用 .NumField().Field(i) 遍历字段;字段名必须通过 .Type().Field(i).Name 获取,不能从 Value 直接读——因为 Value 不带类型元信息。

常见错误:对指针结构体直接传给 reflect.ValueOf,结果得到的是指针的 Value.NumField() 会 panic。得先 .Elem() 解引用:

type User struct {
    Name string
    Age  int
}
u := &User{"Alice", 30}
v 

:= reflect.ValueOf(u).Elem() // 必须 Elem() for i := 0; i < v.NumField(); i++ { field := v.Field(i) name := v.Type().Field(i).Name fmt.Printf("%s: %v\n", name, field.Interface()) }

为什么有些字段反射读不到(空值或 panic)

字段必须是导出的(首字母大写),否则 reflect.Value.Field(i) 会 panic:“cannot set unexported field”。小写字母开头的字段在反射中不可见,哪怕你只是想读取。

另外注意 nil 指针解引用也会 panic:reflect.ValueOf(nil).Elem() 直接崩溃。安全做法是加判断:

  • 检查 v.Kind() == reflect.Ptrv.IsNil() == false.Elem()
  • 检查 v.Kind() == reflect.Struct 才调 .NumField()
  • v.CanInterface() 判断是否允许转回原始类型(避免 “call of reflect.Value.Interface on zero Value”)

struct tag 怎么通过反射读取

结构体字段的 tag(比如 `json:"name"`)不在 Value 上,而属于类型定义,必须用 reflect.Type.Field(i).Tag 获取。常用方法是 tag.Get("json")tag.Lookup("yaml")

注意:tag 字符串需用反引号包裹,且 key 区分大小写;tag.Get("JSON") 返回空字符串,不是 "name"

type Config struct {
    Host string `json:"host" yaml:"server"`
    Port int    `json:"port"`
}
t := reflect.TypeOf(Config{})
field := t.Field(0)
fmt.Println(field.Tag.Get("json")) // "host"
fmt.Println(field.Tag.Get("yaml")) // "server"

反射读结构体性能差在哪,什么情况下该避免

反射涉及运行时类型查找、内存布局解析、接口转换,比直接字段访问慢 10–100 倍。尤其在高频路径(如 HTTP 中间件、序列化循环)中,反复调用 reflect.Value.Field(i).Interface() 会显著拖慢吞吐。

真正需要反射的典型场景只有:通用序列化(json/xml 编码)、ORM 字段映射、配置绑定;其余多数情况可改用接口 + 方法,或代码生成(如 stringereasyjson)绕过反射。

一个容易被忽略的点:reflect.Value 是非类型安全的,一旦字段类型变更(比如 int 改成 int64),编译器不报错,但运行时 .Int().String() 调用会 panic —— 这类问题很难在单元测试里覆盖全。