gostructreflectioninterfacenested

Understand reflection usage with structs and interfaces


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?


Solution

  • 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() {
    

    https://go.dev/play/p/uAfWzYzBmiX