type mcat struct {
ID int
}
type cat struct {
Name string
M mcat
}
func getValue(path string, mcat cat){
//throuth struct path get the value
}
func main(){
mycat := cat{"cat", mcat{1}}
id := getvalue("/M/ID", mycat)
}
Can I do this by reflecting to get a value based on the field name?
You may do what you want with the Value.FieldByName()
function. Just range over the parts of the path which may be splitted using strings.Split()
.
Here's an example:
func getValue(i interface{}, path string) interface{} {
v := reflect.ValueOf(i)
for _, field := range strings.Split(path[1:], "/") {
v = v.FieldByName(field)
}
return v.Interface()
}
func main() {
mycat := cat{"cat", mcat{1}}
id := getValue(mycat, "/M/ID")
fmt.Println(id)
}
It outputs (try it on the Go Playground):
1
Some things to note:
The above solution works for all struct types, not just with cat
. Checks if the passed value is a struct or the field exists is omitted.
I cut of the leading /
of the path with a slice expression: path[1:]
so we don't have to deal with an empty field name inside the loop.
The above getValue()
returns the result as an interface{}
. If you need the ID
as an int
, you may use type assertion like this:
var intID int
intID = id.(int)
Also note that it may be nicer / more useful to use a variadic parameter for the path:
func getValue(i interface{}, path ...string) interface{} {
v := reflect.ValueOf(i)
for _, field := range path {
v = v.FieldByName(field)
}
return v.Interface()
}
func main() {
mycat := cat{"cat", mcat{1}}
id := getValue(mycat, "M", "ID")
fmt.Println(id)
}
Output is the same. Try this one on the Go Playground.