I try to understand the correct usage of reflection with a struct compose by nested structs that implement an interface on Golang;
Here the code:
package main
import (
"log"
"reflect"
)
// Macro is the main struct and contain the two nested structs that implement the interface PrintStr
type Macro struct {
Field1 Test
Field2 Test
}
// PrintStr interface that define a single method Print
type PrintStr interface {
Print() // method that will print the struct content
}
// Test is a simple struct with a single field of type string that implement the PrintStr interface
type Test struct {
str string
}
// Print implementation of interface function
func (t *Test) Print() {
log.Println(t.str)
}
func main() {
test := Macro{
Field1: Test{
str: "field1",
},
Field2: Test{
str: "field2",
},
}
// the idea is to cycle the struct 'test' fields and launch the method Print using the reflection
values := reflect.ValueOf(&test)
if values.Kind() == reflect.Ptr {
values = values.Elem()
}
// cycling the fields
for i := 0; i < values.NumField(); i++ {
switch v := values.Field(i).Interface().(type) {
case PrintStr:
v.Print()
break
default:
log.Fatal("ErrUnhandledType")
}
}
}
if I execute this code, I obtain the follow result:
2025/05/09 15:35:26 ErrUnhandledType
instead, if I edit the switch an I use the Struct that implement the interface...
...
// cycling the fields
for i := 0; i < values.NumField(); i++ {
switch v := values.Field(i).Interface().(type) {
case Test:
v.Print()
break
default:
log.Fatal("ErrUnhandledType")
}
}
...
I obtain the expected result:
2025/05/09 15:47:44 field1
2025/05/09 15:47:44 field2
The final result I want to archive is to create a working code that don't know the final structs that implement the interface PrintStr
ma only the interface itself.
Is this possible?
Because the Print
method is on the pointer receiver, the type Test
does not implement PrintStr
.
Here are two options for fixing the problem.
Option 1: Use the address of the field. The value of values.Field(i).Addr().Interface()
is a *Test
, which does implement the interface.
switch v := values.Field(i).Addr().Interface().(type)
https://go.dev/play/p/ElJamDeiwSB
Option 2: Declare method on value receiver. With this change, type Test
implements the interface.
func (t Test) Print() {