必须先调用.Elem()解引用指针才能遍历结构体字段,否则.NumField()返回0或panic;需确保字段导出(首字母大写)才可安全读取,私有字段反射访问会panic。
怎么用 reflect.Value 遍历结构体字段并读取值
直接用 reflect.ValueOf 获取结构体的反射值后,必须先调用 .Elem()(如果原值是指针),否则会得到指针类型而非结构体本身。常见错误是忘记解引用,导致 .NumField() 返回 0 或 panic。
实操要点:
- 传入结构体变量时,推荐用地址:
reflect.ValueOf(&s),再调用.Elem() - 遍历字段前检查是否为结构体:
v.Kind() == reflect.Struct - 字段值需通过
v.Field(i)获取,不能直接用v.Field(i).Interface()读私有字段(会 panic) - 若要安全读私有字段,得确保该字段是导出的(首字母大写),否则只能用
UnsafeAddr等非常规手段(不推荐)
示例:
type User struct {
Name string
age int // 小写 → 私有 → 反射不可读
}
u := User{Name: "Alice"}
v := reflect.ValueOf(&u).Elem()
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if field.CanInterface() { // 只有导出字段才返回 true
fmt.Println(field.Interface())
}
}
如何用 reflect.Type 获取字段名、类型、标签(tag)
reflect.Type 负责描述“是什么”,比如字段名、类型、结构体标签;而 reflect.Value 负责“值是多少”。两者常配合使用——先用 Type 拿元信息,再用 Value 取值。
关键点:
-
t.Field(i).Name返回字段名(如"Name"),t.Field(i).Type返回字段类型(如string) - 标签需用
t.Field(i).Tag.Get("json")提取,注意 tag 值是字符串字面量,不含引号 - 若字段是嵌套结构体,
t.Field(i).Type.Kind()会是reflect.Struct,可递归处理 - 匿名字段(内嵌)的
t.Field(i).Anonymous为true,其字段会“提升”到外层结构体中
示例(提取 json 标签):