golang中可用reflect包动态获取结构体字段名、类型、标签及值;需注意仅可导出字段能读取值,私有字段仅可读类型和标签;常用于jsON解析、ORM映射等场景。

在 golang 中,可以通过 reflect 包动态获取结构体的字段信息,比如字段名、类型、标签等。这在处理 json 解析、ORM 映射、配置解析等场景中非常有用。
1. 获取结构体字段的基本信息
使用 reflect.typeof 获取结构体类型后,可以通过 NumField 和 Field 方法遍历字段。
示例:
type User struct { Name string `json:"name"` Age int `json:"age"` } func main() { u := User{} t := reflect.TypeOf(u) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fmt.Printf("字段名: %sn", field.Name) fmt.Printf("字段类型: %sn", field.Type) fmt.Printf("JSON 标签: %sn", field.Tag.Get("json")) } }
输出:
立即学习“go语言免费学习笔记(深入)”;
字段名: Name 字段类型: string JSON 标签: name 字段名: Age 字段类型: int JSON 标签: age
2. 读取结构体字段的值
要读取字段的值,需使用 reflect.ValueOf,并确保传入的是可寻址的变量(如指针)。
示例:
func printFieldValue(v Interface{}) { val := reflect.ValueOf(v) if val.Kind() == reflect.Ptr { val = val.Elem() // 解引用指针 } for i := 0; i < val.NumField(); i++ { field := val.Field(i) fmt.Printf("字段值: %vn", field.Interface()) } } // 调用 u := User{Name: "Alice", Age: 30} printFieldValue(u) // 输出: 字段值: Alice, 字段值: 30
3. 处理私有字段和可导出性
只有首字母大写的字段(可导出字段)才能通过反射读取值。如果尝试访问私有字段的值,Field(i).Interface() 会触发 panic。
但可以安全地读取私有字段的类型和标签信息,只要不调用 Interface() 或 Set()。
建议:在使用反射前检查字段是否可导出:
if !field.CanInterface() { fmt.Println("该字段不可访问") continue }
4. 实际应用场景
常见用途包括:
- 自动将结构体字段映射到数据库列(如 ORM)
- 根据 tag 自动校验字段(如 validate tag)
- 实现通用的序列化/反序列化逻辑
例如,构建一个通用的 toMap 函数:
func structToMap(v interface{}) map[string]interface{} { m := make(map[string]interface{}) val := reflect.ValueOf(v) typ := reflect.TypeOf(v) if val.Kind() == reflect.Ptr { val = val.Elem() typ = typ.Elem() } for i := 0; i < val.NumField(); i++ { field := typ.Field(i) m[field.Name] = val.Field(i).Interface() } return m }
基本上就这些。掌握 Type 和 Value 的配合使用,就能灵活操作结构体字段信息。