Go中遍历结构体字段需用reflect包,仅支持导出字段:用reflect.TypeOf获取类型,NumField()和Field(i)遍历,field.Name、field.Type、field.Tag分别获取字段名、类型、标签;非导出字段被忽略。
在 Go 中遍历结构体字段并动态获取字段名和类型,需要借助 reflect 包。Go 的结构体本身不支持原生的运行时字段枚举,但通过反射可以安全、可控地读取公开字段(首字母大写的导出字段)的名称、类型、标签等信息。
先用 reflect.TypeOf 获取结构体的类型对象,再调用 .NumField() 和 .Field(i) 遍历每个字段:
field.Name:字段名(字符串,如 "N
ame")field.Type:字段的类型(reflect.Type),可进一步调用 .Name() 或 .Kind()
field.Tag:结构体标签(如 `json:"name"`),可用 Get("json") 提取注意:只能访问**导出字段**(首字母大写),未导出字段会被忽略且无法通过反射读取值(即使能拿到字段描述,field.Type 可访问,但 reflect.Value.Field(i) 会 panic)。
以下是一个典型用法:
package mainimport ( "fmt" "reflect" )
type User struct { Name string
json:"name"Age intjson:"age"Email stringjson:"email,omitempty"id int // 小写,非导出字段,不会出现在遍历中 }func printStructFields(v interface{}) { t := reflect.TypeOf(v) if t.Kind() == reflect.Ptr { t = t.Elem() } if t.Kind() != reflect.Struct { fmt.Println("不是结构体类型") return }
fmt.Printf("结构体 %s 字段列表:\n", t.Name()) for i := 0; i < t.NumField(); i++ { field := t.Field(i) typeName := field.Type.Name() if typeName == "" && field.Type.Kind() == reflect.Ptr { typeName = "*" + field.Type.Elem().Name() } jsonTag := field.Tag.Get("json") fmt.Printf("- %s: %s (JSON: %q)\n", field.Name, field.Type, jsonTag) }}
func main() { u := User{Name: "Alice", Age: 30} printStructFields(u) // 传值或传指针均可(函数内已处理) }
输出类似:
结构体 User 字段列表: - Name: string (JSON: "name") - Age: int (JSON: "age") - Email: string (JSON: "email,omitempty")获取字段值需配合 reflect.Value
仅获取字段名和类型用
reflect.TypeOf即可;若还需读取当前值,需用reflect.ValueOf,并确保值是可寻址的(如传指针或变量):
v := reflect.ValueOf(&u).Elem() 得到可读写的结构体值v.Field(i).Interface() 获取第 i 个字段的实际值(注意类型断言或 panic 风险)v.Field(i).CanInterface() 返回 false,不能安全取值field.Type.Kind() == reflect.Struct
field.Anonymous 为 true,可据此做特殊处理