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.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.