Reflection can enumerate a struct type's fields and names.

struct fields Use field metadata when a framework or helper needs to inspect the shape of a struct.

Struct Fields

level
struct_fields.go
Replay: real traced execution (multi-file project)
package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name  string
	Level int
}

func main() {
	var level = 3
	user := User{Name: "Ada", Level: level}
	userType := reflect.TypeOf(user)
	firstField := userType.Field(0)
	secondField := userType.Field(1)

	fmt.Println("level=", level)
	fmt.Println("type=", userType.Name())
	fmt.Println("field_count=", userType.NumField())
	fmt.Println("first_field=", firstField.Name)
	fmt.Println("second_type=", secondField.Type.String())
}
package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name  string
	Level int
}

func main() {
	var level = 1
	user := User{Name: "Ada", Level: level}
	userType := reflect.TypeOf(user)
	firstField := userType.Field(0)
	secondField := userType.Field(1)

	fmt.Println("level=", level)
	fmt.Println("type=", userType.Name())
	fmt.Println("field_count=", userType.NumField())
	fmt.Println("first_field=", firstField.Name)
	fmt.Println("second_type=", secondField.Type.String())
}
package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name  string
	Level int
}

func main() {
	var level = 5
	user := User{Name: "Ada", Level: level}
	userType := reflect.TypeOf(user)
	firstField := userType.Field(0)
	secondField := userType.Field(1)

	fmt.Println("level=", level)
	fmt.Println("type=", userType.Name())
	fmt.Println("field_count=", userType.NumField())
	fmt.Println("first_field=", firstField.Name)
	fmt.Println("second_type=", secondField.Type.String())
}
  1. level ← 3, user ← main.User{Name:"Ada", Level:3}, userType ← &reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}

    13func main() {14  var level→ 3 = 3 //@level=1, 515  user→ main.User{Name:"Ada", Level:3} := User{Name: "Ada", Level: level3}16  userType→ &reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}} := reflect.TypeOf(usermain.User{Name:"Ada", Level:3})17  firstField→ reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(⟨addr D⟩), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false} := userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Field(0)18  secondField→ reflect.StructField{Name:"Level", PkgPath:"", Type:(*reflect.rtype)(⟨addr E⟩), Tag:"", Offset:0x10, Index:[]int{1}, Anonymous:false} := userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Field(1)1920  fmt.Println("level=", level3)21  fmt.Println("type=", userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Name())22  fmt.Println("field_count=", userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.NumField())23  fmt.Println("first_field=", firstField.Name"Name")24  fmt.Println("second_type=", secondField.Type&reflect.rtype{t:abi.Type{Size_:0x8, PtrBytes:0x0, Hash:⟨addr F⟩, TFlag:0xf, Align_:0x8, FieldAlign_:0x8, Kind_:0x2, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr G⟩), GCData:(*uint8)(⟨addr H⟩), Str:814, PtrToThis:20608}}.String())25}
    outputlevel= 3
    type= User
    field_count= 2
    first_field= Name
    second_type= int
  1. level ← 1, user ← main.User{Name:"Ada", Level:1}, userType ← &reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}

    13func main() {14  var level→ 1 = 115  user→ main.User{Name:"Ada", Level:1} := User{Name: "Ada", Level: level1}16  userType→ &reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}} := reflect.TypeOf(usermain.User{Name:"Ada", Level:1})17  firstField→ reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(⟨addr D⟩), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false} := userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Field(0)18  secondField→ reflect.StructField{Name:"Level", PkgPath:"", Type:(*reflect.rtype)(⟨addr E⟩), Tag:"", Offset:0x10, Index:[]int{1}, Anonymous:false} := userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Field(1)1920  fmt.Println("level=", level1)21  fmt.Println("type=", userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Name())22  fmt.Println("field_count=", userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.NumField())23  fmt.Println("first_field=", firstField.Name"Name")24  fmt.Println("second_type=", secondField.Type&reflect.rtype{t:abi.Type{Size_:0x8, PtrBytes:0x0, Hash:⟨addr F⟩, TFlag:0xf, Align_:0x8, FieldAlign_:0x8, Kind_:0x2, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr G⟩), GCData:(*uint8)(⟨addr H⟩), Str:814, PtrToThis:20608}}.String())25}
    outputlevel= 1
    type= User
    field_count= 2
    first_field= Name
    second_type= int
  1. level ← 5, user ← main.User{Name:"Ada", Level:5}, userType ← &reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}

    13func main() {14  var level→ 5 = 515  user→ main.User{Name:"Ada", Level:5} := User{Name: "Ada", Level: level5}16  userType→ &reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}} := reflect.TypeOf(usermain.User{Name:"Ada", Level:5})17  firstField→ reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(⟨addr D⟩), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false} := userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Field(0)18  secondField→ reflect.StructField{Name:"Level", PkgPath:"", Type:(*reflect.rtype)(⟨addr E⟩), Tag:"", Offset:0x10, Index:[]int{1}, Anonymous:false} := userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Field(1)1920  fmt.Println("level=", level5)21  fmt.Println("type=", userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.Name())22  fmt.Println("field_count=", userType&reflect.rtype{t:abi.Type{Size_:0x18, PtrBytes:0x8, Hash:⟨addr A⟩, TFlag:0x7, Align_:0x8, FieldAlign_:0x8, Kind_:0x19, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr B⟩), GCData:(*uint8)(⟨addr C⟩), Str:6806, PtrToThis:19136}}.NumField())23  fmt.Println("first_field=", firstField.Name"Name")24  fmt.Println("second_type=", secondField.Type&reflect.rtype{t:abi.Type{Size_:0x8, PtrBytes:0x0, Hash:⟨addr F⟩, TFlag:0xf, Align_:0x8, FieldAlign_:0x8, Kind_:0x2, Equal:(func(unsafe.Pointer, unsafe.Pointer) bool)(⟨addr G⟩), GCData:(*uint8)(⟨addr H⟩), Str:814, PtrToThis:20608}}.String())25}
    outputlevel= 5
    type= User
    field_count= 2
    first_field= Name
    second_type= int