I have a struct
that has one or more struct
members. Each member is expected to implement a Validator
interface.
I want to use reflection to iterate over all struct
members and call the interface's Validate()
method. For example:
package main
import "fmt"
import "reflect"
type Validator interface {
Validate()
}
type T1 struct {
S string
}
func (p *T1) Validate() {
fmt.Println("HERE 1")
}
type T2 struct {
S string
}
func (p *T2) Validate() {
fmt.Println("HERE 2")
}
type Top struct {
S1 T1
S2 T2
}
func main() {
var t Top
r := reflect.ValueOf(t)
for i := 0; i < r.NumField(); i++ {
f := r.Field(i)
if f.Kind() == reflect.Struct {
validator := f.Interface().(Validator)
validator.Validate()
}
}
}
When run, it outputs:
panic: interface conversion: main.T1 is not main.Validator: missing method Validate
If I change the Validate()
methods to accept value (rather than pointer) receivers, then it works. However, I want to use pointer receivers since the struct
s may grow to be large.
How can I change the reflection code to work where the methods are defined taking pointer receivers?
I also tried using this line:
validator := f.Addr().Interface().(Validator)
to get a pointer, but it then outputs:
panic: reflect.Value.Addr of unaddressable value
None of your values are addressable, so you can't call any methods on them with pointer receivers.
If the S1
and S2
fields can't be pointers, you can still address them if you have a pointer to the Top
struct:
r := reflect.ValueOf(&t).Elem()
for i := 0; i < r.NumField(); i++ {
f := r.Field(i)
if f.Kind() == reflect.Struct {
validator := f.Addr().Interface().(Validator)
validator.Validate()
}
}
"Top.S1" is of type "T1" and is different from "*T1" type defined "Validate()".
If you change "Top.S1" to "*T1" type and modify the field type checking, your code will work properly.
type Top struct {
S1 *T1
S2 *T2
}
func main() {
t := Top{&T1{}, &T2{}}
r := reflect.ValueOf(t)
for i := 0; i < r.NumField(); i++ {
f := r.Field(i)
if f.Kind() == reflect.Ptr && f.Elem().Kind() == reflect.Struct {
validator, ok := f.Interface().(Validator)
if ok {
validator.Validate()
} else {
fmt.Println("not ok")
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.