Get value of pointer of a struct field using reflect - go

package main
import (
"fmt"
"reflect"
)
type PetDetails struct {
Name *string
}
type Student struct {
Fname string
Lname string
City string
Mobile *int
Pet *PetDetails
}
func main() {
i := 7777777777
petName := "Groot"
s := Student{"Chetan", "Tulsyan", "Bangalore", &i, &PetDetails{&petName}}
v := reflect.ValueOf(s)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
}
}
I am trying to convert these struct into map[string]string as I need the map for update query of mongoDB. After converting my struct to BSON, instead of querying { "pet.name": "Groot" } it becomes { "pet": { "name": "Groot" } } which deletes other fields inside the embedded document pet. I'm not sure how to override BSON marshals as I'm using mongodb driver, not mgo
I would like to get value of Mobile pointer and Name of the Pet, but all I get is the address
How can I get the value, e.g. 7777 and Groot ? Thanks

You can use Elem to dereference the pointer types.
x := 5
ptr := reflect.ValueOf(&x)
value := ptr.Elem()
ptr.Type().Name() // *int
ptr.Type().Kind() // reflect.Ptr
ptr.Interface() // [pointer to x]
ptr.Set(4) // panic
value.Type().Name() // int
value.Type().Kind() // reflect.Int
value.Interface() // 5
value.Set(4) // this works
For example, to retrieve the mobile number in your example you should change the loop in main to:
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
value := field.Interface()
// If a pointer type dereference with Elem
if field.Kind() == reflect.Ptr {
value = field.Elem().Interface()
}
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, value)
}

Related

Obtain structure info

The program is:
package main
import (
"fmt"
"reflect"
)
type Request struct {
Method string
Resource string //path
Protocol string
}
type s struct {
ID int
Title string
Request Request
Price float64
Interface interface{}
Exists bool
Many []string
}
func main() {
s := s{}
iterateStruct(s)
}
func iterateStruct(s interface{}) {
e := reflect.ValueOf(s)
for i := 0; i < e.NumField(); i++ {
varName := e.Type().Field(i).Name
varKind := e.Field(i).Kind()
fmt.Println(e.Type().Field(i).Name)
if varKind == reflect.Struct {
//iterateStruct( <what should be here?>)
}
varType := e.Type().Field(i).Type
varValue := e.Field(i).Interface()
fmt.Printf("%v %v %v %v\n", varName, varKind, varType, varValue)
}
}
Using recursion I'd like to get the same information for Request, that is a structure part of a structure.
What would I need to pass as a parameter? I tried various ways but I have to reckon it's a lot of trial and error for me.
Try this:
if varKind == reflect.Struct {
iterateStruct(e.Field(i).Interface())
}
e.Field(i) returns the Value for the struct field. Interface{} will return the underlying value, so you can call iterateStruct using that.
Here's an example that handles fields with pointers to structs, interfaces containing struct value, etc.. As a bonus, this example indents nested structs.
func iterate(v reflect.Value, indent string) {
v = reflect.Indirect(v)
if v.Kind() != reflect.Struct {
return
}
indent += " "
for i := 0; i < v.NumField(); i++ {
varName := v.Type().Field(i).Name
varKind := v.Field(i).Kind()
varType := v.Type().Field(i).Type
varValue := v.Field(i).Interface()
fmt.Printf("%s%v %v %v %v\n", indent, varName, varKind, varType, varValue)
iterate(v.Field(i), indent)
}
}
Call it like this:
iterate(reflect.ValueOf(s), "")
https://go.dev/play/p/y1CzbKAUvD_w

How to update the values of an interface within a function with the type defined at runtime?

Let's say I have a struct User
type User struct {
Name string `owm:"newNameFromAPI"`
}
The code below initialises the struct and passes it to a function
func main() {
dest := User{
Name: "Sebastien",
}
deepUpdate(dest, "owm")
}
The function uses reflect in order to iterate over all the fields of the struct and update them accordingly (several chunks of code were removed for clarity)
func deepUpdate(destinationInterface interface{}, selector string) {
// Here I'm not supposed to know that the type is `User`
// And if I just use dest := destinationInterface, the value won't update
dest := destinationInterface.(User)
// Pointer to struct - addressable
destVal := reflect.ValueOf(&dest)
destType := reflect.TypeOf(&dest)
// psindirect := reflect.Indirect(destVal) // ? ValueOf(<Ptr Value>) Requires to be adressed via reflect.Indirect() to access Field - https://stackoverflow.com/a/50098755/9077800
// Struct
destValElem := destVal.Elem()
destTypeElem := destType.Elem()
// Iterate over all fields of the struct
for i := 0; i < destValElem.NumField(); i++ {
// // for i := 0; i < destTypeElem.NumField(); i++ {
destValField := destValElem.Field(i)
destTypeField := destTypeElem.Field(i)
switch destValField.Kind() {
// Field is a struct
case reflect.Struct:
// Recursion
fmt.Println("IS A STRUCT")
default:
// Get the complete tag
tag := destTypeField.Tag
if len(tag) == 0 {
continue
}
// Get the value of our custom tag key
tagVal := tag.Get(selector)
if len(tagVal) == 0 {
continue
}
// Access the value in our source data, thanks to a dot notation access - example: "user.profile.firstname"
sourceValue := "John" // tee.Get(sourceInterface, tagVal)
// Exported field
f := destValField
if f.IsValid() {
// A Value can be changed only if it is
// addressable and was not obtained by
// the use of unexported struct fields.
if f.CanSet() {
// Change value of Name
fv := reflect.ValueOf(sourceValue)
destValField.Set(fv)
}
}
fmt.Println("NOT STRUCT")
}
}
fmt.Println(dest.Name)
}
The problem is the following line, because I'm not supposed to know that the destinationInterface is to be casted to User.
How can I dynamically cast the interface to some unknown type defined at runtime, or any other way to get the same output of the updated Name "John" instead of "Sebastien"?
dest := destinationInterface.(User)
Here is the complete code running on the golang playgound
https://play.golang.org/p/sYvz-Fwp97P
You don't have to know the type of dest. The example is not recursive, but it can be easily upgraded.
package main
import (
"fmt"
"reflect"
)
type User struct {
Name string `owm:"newNameFromAPI"`
}
func main() {
dest := User{
Name: "Sebastien",
}
fmt.Println("Before:", dest.Name)
deepUpdate(&dest, "owm")
fmt.Println("After:", dest.Name)
}
func deepUpdate(dest interface{}, selector string) {
//Get the reflect value of dest
rv := reflect.ValueOf(dest)
//Dereference every pointers
for rv.Kind() == reflect.Ptr {
rv = reflect.Indirect(rv)
}
//Check if its a struct, should use panic or return error
if reflect.TypeOf(rv.Interface()).Kind() != reflect.Struct {
fmt.Println("NOT A STRUCT")
return
}
//Loop over the fields
for i := 0; i < rv.NumField(); i++ {
//Get the tag value
tag := rv.Type().Field(i).Tag.Get(selector)
if tag == "" {
continue
}
//Get the source
sourceValue := "John"
//Assign the source to the dest's corresponding field
if rv.Field(i).CanSet() {
rv.Field(i).Set(reflect.ValueOf(sourceValue))
}
}
}
The only thing is that you have to use the same type for sourceValue that the corresponding field is.
Working example: https://goplay.space/#D0CmTaS5AiP

Lookup a tag by field symbol in Go

Given a structure with fields I'd like to lookup tag value for particular field symbolically (without providing field name as string).
type MyStruct struct {
Foo string `tag:"val"`
}
entity := MyStruct{}
tagVal := getTag(&entity.Foo) // the function would return "val" for Foo field
I'd like to implement a getTag function that would return tag value for a given field.
Pointer to field value does no contain any information about owner structure, that's a different way of indirection, so having only a pointer field value is not enough to solve the problem.
One solution could be to use pointer to owner structure together with pointer to the field in that structure, iterate fields of that structure value with reflection until the address of iterated field matches given field value pointer.
https://play.golang.org/p/kaPQ9HF9wAK
package main
import (
"fmt"
"reflect"
)
func main() {
type MyStruct struct {
Foo string `tag:"val"`
}
entity := MyStruct{}
tagVal := getTag(&entity, &entity.Foo)
fmt.Println(tagVal) // val
}
func getTag(structPtr, fieldPtr interface{}) string {
sf, ok := structFieldByValPtr(structPtr, fieldPtr)
if !ok {
return ""
}
return sf.Tag.Get("tag")
}
func structFieldByValPtr(structPtr, fieldPtr interface{}) (reflect.StructField, bool) {
v := reflect.Indirect(reflect.ValueOf(structPtr))
t := v.Type()
for i := 0; i < v.NumField(); i++ {
fv := v.Field(i)
ft := t.Field(i)
if fv.Addr().Interface() == fieldPtr {
return ft, true
}
if ft.Anonymous {
sf, ok := structFieldByValPtr(fv.Addr().Interface(), fieldPtr)
if ok {
return sf, true
}
}
}
return reflect.StructField{}, false
}

How to copy a non-pointer value to a pointer indirected value via reflection

I want the Set method below to set the APtr field of a passed in B struct to a value that gets passed in by value, i.e. without a pointer indirection.
For that to work via go reflection, I will probably have to copy that value to a new location that I have the address of? Either way, how can I get this to work? What I have is a working version for non-pointers values.
type A struct {
AnInt int
}
type B struct {
AnA A
APtr *A
}
func Set(strukt interface{}, fieldName string, newFieldValue interface{}) {
struktValueElem := reflect.ValueOf(strukt).Elem()
field := struktValueElem.FieldByName(fieldName)
newFieldValueValue := reflect.ValueOf(newFieldValue)
if field.Kind() == reflect.Ptr {
// ?? implement me
} else { // not a pointer? more straightforward:
field.Set(newFieldValueValue)
}
}
func main() {
aB := B{}
anA := A{4}
Set(&aB, "AnA", anA) // works
Set(&aB, "APtr", anA) // implement me
}
Playground: https://play.golang.org/p/6tcmbXxBcIm
func Set(strukt interface{}, fieldName string, newFieldValue interface{}) {
struktValueElem := reflect.ValueOf(strukt).Elem()
field := struktValueElem.FieldByName(fieldName)
newFieldValueValue := reflect.ValueOf(newFieldValue)
if field.Kind() == reflect.Ptr {
rt := field.Type() // type *A
rt = rt.Elem() // type A
rv := reflect.New(rt) // value *A
el := rv.Elem() // value A (addressable)
el.Set(newFieldValueValue) // el is addressable and has the same type as newFieldValueValue (A), Set can be used
field.Set(rv) // field is addressable and has the same type as rv (*A), Set can be used
} else { // not a pointer? more straightforward:
field.Set(newFieldValueValue)
}
}
https://play.golang.org/p/jgEK_rKbgO9
https://play.golang.org/p/B6vOONQ-RXO (compact)

Iterate through the fields of a struct in Go

Basically, the only way (that I know of) to iterate through the values of the fields of a struct is like this:
type Example struct {
a_number uint32
a_string string
}
//...
r := &Example{(2 << 31) - 1, "...."}:
for _, d:= range []interface{}{ r.a_number, r.a_string, } {
//do something with the d
}
I was wondering, if there's a better and more versatile way of achieving []interface{}{ r.a_number, r.a_string, }, so I don't need to list each parameter individually, or alternatively, is there a better way to loop through a struct?
I tried to look through the reflect package, but I hit a wall, because I'm not sure what to do once I retrieve reflect.ValueOf(*r).Field(0).
Thanks!
After you've retrieved the reflect.Value of the field by using Field(i) you can get a
interface value from it by calling Interface(). Said interface value then represents the
value of the field.
There is no function to convert the value of the field to a concrete type as there are,
as you may know, no generics in go. Thus, there is no function with the signature GetValue() T
with T being the type of that field (which changes of course, depending on the field).
The closest you can achieve in go is GetValue() interface{} and this is exactly what reflect.Value.Interface()
offers.
The following code illustrates how to get the values of each exported field in a struct
using reflection (play):
import (
"fmt"
"reflect"
)
func main() {
x := struct{Foo string; Bar int }{"foo", 2}
v := reflect.ValueOf(x)
values := make([]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
values[i] = v.Field(i).Interface()
}
fmt.Println(values)
}
If you want to Iterate through the Fields and Values of a struct then you can use the below Go code as a reference.
package main
import (
"fmt"
"reflect"
)
type Student struct {
Fname string
Lname string
City string
Mobile int64
}
func main() {
s := Student{"Chetan", "Kumar", "Bangalore", 7777777777}
v := reflect.ValueOf(s)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
fmt.Printf("Field: %s\tValue: %v\n", typeOfS.Field(i).Name, v.Field(i).Interface())
}
}
Run in playground
Note: If the Fields in your struct are not exported then the v.Field(i).Interface() will give panic panic: reflect.Value.Interface: cannot return value obtained from unexported field or method.
Go 1.17 (Q3 2021) should add a new option, through commit 009bfea and CL 281233, fixing issue 42782.
reflect: add VisibleFields function
When writing code that reflects over a struct type, it's a common requirement to know the full set of struct fields, including fields available due to embedding of anonymous members while excluding fields that are erased because they're at the same level as another field with the same name.
The logic to do this is not that complex, but it's a little subtle and easy to get wrong.
This CL adds a new reflect.VisibleFields() function to the reflect package that returns the full set of effective fields that apply in a given struct type.
fields := reflect.VisibleFields(typ)
for j, field := range fields {
...
}
Example,
type employeeDetails struct {
id int16
name string
designation string
}
func structIterator() {
fields := reflect.VisibleFields(reflect.TypeOf(struct{ employeeDetails }{}))
for _, field := range fields {
fmt.Printf("Key: %s\tType: %s\n", field.Name, field.Type)
}
}
Maybe too late :))) but there is another solution that you can find the key and value of structs and iterate over that
package main
import (
"fmt"
"reflect"
)
type person struct {
firsName string
lastName string
iceCream []string
}
func main() {
u := struct {
myMap map[int]int
mySlice []string
myPerson person
}{
myMap: map[int]int{1: 10, 2: 20},
mySlice: []string{"red", "green"},
myPerson: person{
firsName: "Esmaeil",
lastName: "Abedi",
iceCream: []string{"Vanilla", "chocolate"},
},
}
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Type().Field(i).Name)
fmt.Println("\t", v.Field(i))
}
}
and there is no *panic* for v.Field(i)
use this:
type x struct {
Id int
jsj int
}
func main() {
x2 := x{jsj: 10, Id: 5}
v := reflect.ValueOf(x2)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
}
====>10
====>5
Taking Chetan Kumar solution and in case you need to apply to a map[string]int
package main
import (
"fmt"
"reflect"
)
type BaseStats struct {
Hp int
HpMax int
Mp int
MpMax int
Strength int
Speed int
Intelligence int
}
type Stats struct {
Base map[string]int
Modifiers []string
}
func StatsCreate(stats BaseStats) Stats {
s := Stats{
Base: make(map[string]int),
}
//Iterate through the fields of a struct
v := reflect.ValueOf(stats)
typeOfS := v.Type()
for i := 0; i< v.NumField(); i++ {
val := v.Field(i).Interface().(int)
s.Base[typeOfS.Field(i).Name] = val
}
return s
}
func (s Stats) GetBaseStat(id string) int {
return s.Base[id]
}
func main() {
m := StatsCreate(BaseStats{300, 300, 300, 300, 10, 10, 10})
fmt.Println(m.GetBaseStat("Hp"))
}
Use reflect package. First, get the type of variable with reflect.TypeOf and get numbers of elements with reflect.NumField.To obtain the values of the fields iteratively of a structure must reflect the variable and use the function rg.Elem().Field(i)
package main
import (
"fmt"
"reflect"
)
type Gopher struct {
Name string
Color string
Year int
}
func main() {
g := Gopher{Name: "AAA", Color: "BBBB", Year: 2021}
gtype := reflect.TypeOf(g)
numFields := gtype.NumField()
rg := reflect.ValueOf(&g)
for i := 0; i < numFields; i++ {
fmt.Println(rg.Elem().Field(i))
}
}
In Go, you can use the reflect package to iterate through the fields of a struct. The reflect package allows you to inspect the properties of values at runtime, including their type and value. Here's an example of how to iterate through the fields of a struct:
Go Playground
package main
import (
"fmt"
"reflect"
)
type Movie struct {
Name string
Year int
}
func main() {
p := Movie{"The Dark Knight", 2008}
val := reflect.ValueOf(p)
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
fieldType := typ.Field(i)
fmt.Printf("Field Name: %s, Field Value: %v\n", fieldType.Name, field.Interface())
}
}
Output:
Field Name: Name, Field Value: The Dark Knight
Field Name: Age, Field Value: 2008

Resources