Trying to get function with reflect from an embedded type

I’m trying to get a method from a type embedded in a type a few calls down in methods. I’ve got the code here (cleaned up so you only need to look at what’s needed for the problem) https://play.golang.org/p/p1nhHxJe2e2 .

The line I am trying to get to work is m := vField.MethodByName("Validate") to get access to the method func (tz *TZConfig) Validate(...) .

This is just part of some initialization so using reflect and perhaps being a little slower than written other ways is not an issue.

A clue as to what I am missing to make this work would be much appreciated.

And here is what’s in the playground link:

package main

import (
	`fmt`
	`os`
	`reflect`
	`time`
)

var Config Configuration

type Configuration struct {
	Core CoreConfig
}

type CoreConfig struct {
	// Other stuff
	Database DatabaseConfig
}

type DatabaseConfig struct {
	User             string   `validate:"required=true,min=1,max=80"`
	Loc              TZConfig ``
}

type TZConfig struct {
	String string
	TZ     *time.Location
}

func main() {
	if err := Config.validate(); err != nil {
		os.Exit(1)
	}
}

func (c *Configuration) validate() error {
	return c.Core.validate()
}

func (core *CoreConfig) validate() error {
	var err error
	errs := 0
	ancestry := `core`

	core.Database.validate(core, ancestry, &errs)

	return err
}

func (db *DatabaseConfig) validate(parent interface{}, ancestry string, errs *int) {
	ancestry = ancestry+`.Database`

	veParent := reflect.ValueOf(db).Elem()
	for i := 0; i < veParent.NumField(); i++ {
		vField := veParent.Field(i)
		sField := veParent.Type().Field(i)

		if sField.Name == `Loc` {
			m := vField.MethodByName(`Validate`)
			fmt.Println(m)
		} else {
			// Stuff
		}
	}
	_ = ancestry // Just to throw a breakpoint on
}

func (tz *TZConfig) Validate(ancestry string, required bool, errs *int) {
	if tz.TZ == nil {
		if required {
			// show error
		}
		if len(tz.String) > 0 {
			// Show error
		}
	}
}

Thanks for boiling it down to a minimal scenario. It made it easy to test with!

The issue is that your Loc field is a TZConfig struct value but Validate operates on a TZConfig pointer. To make it work, all you have to do is change line #60 to:

m := vField.Addr().MethodByName(`Validate`)

@skillian Awesome, thank you!

I gather that’s because the method has a pointer func (tz *TZConfig)...? I would have thought that I would need to do that if I added Loc as *TZConfig if I did would that mean that I would need to get to it through something like

m := vField.Addr().Addr().MethodByName(`Validate`)

Which intuitively seems like there would be something wrong to have to do that.