Using reflect, iterate a pointer-to-struct's fields
Tests fluency with Go reflection for indirection and field traversal. Outline: ValueOf/TypeOf, guard IsValid, check Kind==Ptr, Elem to struct, loop NumField with Type for names and Value for values. Red flag: Field() on the pointer before Elem panics.
WHAT THIS TESTS: This question probes whether you understand the dual nature of Go's reflect package: reflect.Type describes the schema while reflect.Value holds the actual data. It specifically checks if you know how to safely navigate pointer indirection, validate kinds before calling type-specific methods, and iterate struct fields without causing a runtime panic. Interviewers also listen for awareness of package-level constants like reflect.Ptr and reflect.Struct versus the more general category kinds.
A GOOD ANSWER COVERS: First, obtain both views by calling reflect.TypeOf and reflect.ValueOf on the input, and immediately guard against invalid or nil input using IsValid and optionally IsNil. Second, check that the Value's Kind equals reflect.Ptr; if so, call Elem to dereference it, then verify the resulting Kind equals reflect.Struct. Third, loop from zero to the struct Value's NumField minus one. Inside the loop, use the Type's Field method to get the StructField which carries the Name, and use the Value's Field method to get a Value representing the field's data. Fourth, safely print values by calling Interface on each field Value, but only after confirming CanInterface returns true, because Interface panics on unexported fields. Optionally mention that if you only need fmt.Printf formatting, you can skip Interface and use the Value directly, or that you could use a type switch for primitive kinds if you need custom formatting.
COMMON WRONG ANSWERS: Calling NumField or Field directly on the original pointer Value instead of on the result of Elem; this always panics because a pointer has no fields. Using TypeOf on the dereferenced Value but forgetting to also call Elem on the Value side, leaving you with a pointer Value that cannot yield field data. Assuming all fields can be converted via Interface and getting a runtime panic on unexported fields. Conflating reflect.Ptr with reflect.Interface and attempting Elem on an interface type rather than the expected pointer. Another subtle mistake is ignoring IsNil on pointer Values, which can lead to panics when calling Elem on a nil pointer.
LIKELY FOLLOW-UPS: How would you recursively handle nested structs or slices of structs? What if the requirement changes to modifying fields instead of printing them, and how does addressability affect Set? How does the performance of reflection compare to direct access or code generation? What is the difference between VisibleFields and the older FieldByIndex behavior? Can you use struct tags to filter or rename output, and how does Tag.Lookup work?
ONE CONCRETE EXAMPLE: func Inspect(v any) { val := reflect.ValueOf(v); if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() { return } val = val.Elem(); if val.Kind() != reflect.Struct { return } typ := val.Type(); for i := 0; i < val.NumField(); i++ { fieldVal := val.Field(i); name := typ.Field(i).Name; if fieldVal.CanInterface() { fmt.Printf("%s: %v\n", name, fieldVal.Interface()) } else { fmt.Printf("%s: <unexported>\n", name) } } }
Read the original → pkg.go.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.