Golang中如何通过反射访问子结构体
Golang中如何通过反射访问子结构体 我正在编写一个通用的JSON解析器,它有一些内置解析器无法满足的要求。我可以将JSON解析到一个映射中,然后将值分配给字段。但是,当我有一个结构体嵌套在另一个结构体中时,它就不再起作用了。
以下是一个不起作用的示例:
https://play.golang.org/p/UvSl3wl9U_p
注意 这是一个模块的通用方法。因此,在编译时我不知道被解析结构体的类型,所以我无法直接将其类型转换为childNode。
2 回复
在第115行,您正在创建一个指向 reflect.Value 的指针的 reflect.Value:
childV := reflect.ValueOf(&f)
相反,我建议您获取字段的地址,这样当您递归进入 writeValuesReflected 时,对 Elem() 的调用就能获取到正确的值:
childV := f.Addr()
更多关于Golang中如何通过反射访问子结构体的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中通过反射访问嵌套结构体字段时,需要递归遍历结构体。以下是针对您问题的解决方案:
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Parent struct {
Name string
Child Child
Value int
}
type Child struct {
Name string
Age int
}
func main() {
jsonStr := `{"Name":"Parent1","Child":{"Name":"Child1","Age":10},"Value":100}`
// 创建父结构体实例
parent := &Parent{}
// 解析JSON到map
var data map[string]interface{}
json.Unmarshal([]byte(jsonStr), &data)
// 使用反射设置值
setStructFields(parent, data)
fmt.Printf("Parent: %+v\n", parent)
fmt.Printf("Child Name: %s\n", parent.Child.Name)
fmt.Printf("Child Age: %d\n", parent.Child.Age)
}
func setStructFields(obj interface{}, data map[string]interface{}) {
v := reflect.ValueOf(obj).Elem()
t := v.Type()
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := t.Field(i)
fieldName := fieldType.Name
// 检查map中是否存在该字段
if value, exists := data[fieldName]; exists {
// 处理嵌套结构体
if field.Kind() == reflect.Struct {
// 递归处理嵌套结构体
if nestedMap, ok := value.(map[string]interface{}); ok {
// 创建嵌套结构体的指针
nestedPtr := reflect.New(field.Type())
setStructFields(nestedPtr.Interface(), nestedMap)
field.Set(nestedPtr.Elem())
}
} else {
// 设置基本类型字段
setFieldValue(field, value)
}
}
}
}
func setFieldValue(field reflect.Value, value interface{}) {
switch field.Kind() {
case reflect.String:
if str, ok := value.(string); ok {
field.SetString(str)
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if num, ok := value.(float64); ok {
field.SetInt(int64(num))
}
case reflect.Float32, reflect.Float64:
if num, ok := value.(float64); ok {
field.SetFloat(num)
}
case reflect.Bool:
if b, ok := value.(bool); ok {
field.SetBool(b)
}
}
}
对于更通用的解决方案,这里提供一个可以处理任意深度嵌套结构体的版本:
func setNestedField(obj interface{}, data map[string]interface{}) error {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr || v.IsNil() {
return fmt.Errorf("obj must be a non-nil pointer")
}
v = v.Elem()
if v.Kind() != reflect.Struct {
return fmt.Errorf("obj must point to a struct")
}
return setStructFieldsRecursive(v, data)
}
func setStructFieldsRecursive(v reflect.Value, data map[string]interface{}) error {
t := v.Type()
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := t.Field(i)
fieldName := fieldType.Name
if value, exists := data[fieldName]; exists {
// 处理嵌套结构体
if field.Kind() == reflect.Struct {
if nestedMap, ok := value.(map[string]interface{}); ok {
// 递归设置嵌套结构体字段
if err := setStructFieldsRecursive(field, nestedMap); err != nil {
return err
}
}
} else if field.Kind() == reflect.Ptr && field.Type().Elem().Kind() == reflect.Struct {
// 处理指针类型的嵌套结构体
if nestedMap, ok := value.(map[string]interface{}); ok {
// 创建新实例
nestedPtr := reflect.New(field.Type().Elem())
if err := setStructFieldsRecursive(nestedPtr.Elem(), nestedMap); err != nil {
return err
}
field.Set(nestedPtr)
}
} else {
// 设置基本类型字段
if err := setFieldWithTypeCheck(field, value); err != nil {
return err
}
}
}
}
return nil
}
func setFieldWithTypeCheck(field reflect.Value, value interface{}) error {
fieldType := field.Type()
switch field.Kind() {
case reflect.String:
if str, ok := value.(string); ok {
field.SetString(str)
return nil
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch v := value.(type) {
case float64:
field.SetInt(int64(v))
return nil
case int:
field.SetInt(int64(v))
return nil
}
case reflect.Float32, reflect.Float64:
if num, ok := value.(float64); ok {
field.SetFloat(num)
return nil
}
case reflect.Bool:
if b, ok := value.(bool); ok {
field.SetBool(b)
return nil
}
}
return fmt.Errorf("type mismatch for field: expected %v, got %T", fieldType, value)
}
这个实现可以处理:
- 任意深度的嵌套结构体
- 结构体指针类型的嵌套字段
- 类型安全检查
- 递归遍历所有嵌套层级
使用示例:
type GrandChild struct {
Name string
}
type Child struct {
Name string
GrandChild GrandChild
}
type Parent struct {
Name string
Child *Child
}
func main() {
jsonStr := `{"Name":"Parent1","Child":{"Name":"Child1","GrandChild":{"Name":"GrandChild1"}}}`
parent := &Parent{}
var data map[string]interface{}
json.Unmarshal([]byte(jsonStr), &data)
if err := setNestedField(parent, data); err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Parent: %+v\n", parent)
fmt.Printf("Child: %+v\n", parent.Child)
fmt.Printf("GrandChild: %+v\n", parent.Child.GrandChild)
}

