Generic unmarshalling in Go - pointers

I'm trying to figure out if there is a way to unmarshal JSON strings to a specific struct, using only the string and the intended type. Here is what I have come up with so far.
Code
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
}
func genericUnmarshal(jsonString string, t reflect.Type) interface{} {
p := reflect.New(t)
result := p.Interface()
json.Unmarshal([]byte(jsonString), &result)
return result
}
func main() {
jsonData := "{\"name\":\"John\"}"
unmarshalledPerson := genericUnmarshal(jsonData, reflect.TypeOf(Person{}))
person := Person{Name: "John"}
fmt.Printf("struct value: %+v type: %+v\n", person, reflect.TypeOf(person))
fmt.Printf("unmarshalled value: %+v type: %+v\n", unmarshalledPerson, reflect.TypeOf(unmarshalledPerson))
fmt.Printf("are variables equal: %v\n", reflect.DeepEqual(unmarshalledPerson, person))
}
Returns
struct value: {Name:John} type: main.Person
unmarshalled value: &{Name:John} type: *main.Person
are variables equal: false
The method genericUnmarshal returns a pointer to the type.
My question: Is there a way change the unmarshalled value into a struct (i.e. Person) instead of a pointer, so that reflect.DeepEqual(unmarshalledPerson, person) returns true?

You may compare person pointers, because reflect.DeepEqual() also accepts if the pointed values are (deeply) equal:
Pointer values are deeply equal if they are equal using Go's == operator or if they point to deeply equal values.
So simply do:
fmt.Printf("are variables equal: %v\n",
reflect.DeepEqual(unmarshalledPerson, &person))
Or dereference the *Person pointer wrapped inside unmarshalledPerson so you get a Person struct:
fmt.Printf("are variables equal: %v\n",
reflect.DeepEqual(*unmarshalledPerson.(*Person), person))
Both prints true (try it on the Go Playground):
are variables equal: true
are variables equal: true
Also note that for your "simple" struct you may use simple == comparison:
*unmarshalledPerson.(*Person) == person
This won't be the case if you add other fields such as pointers, structs, maps etc.

Related

How can I reverse map using reflection

I am studying reflect in Go and trying to implement function which get map and return another map, where keys will be values and values will be keys.
Example:
m := map[string]int{"one": 1, "two": 2}
fmt.Println(ReverseMap(m)) // {1: "one", 2: "two"}
Here is my code:
func ReverseMap(in interface{}) interface{} {
var out reflect.Value
v := reflect.ValueOf(in)
if v.Kind() == reflect.Map {
for idx, key := range v.MapKeys() {
value := v.MapIndex(key)
if idx == 0 {
mapType := reflect.MapOf(reflect.TypeOf(value), reflect.TypeOf(key))
out = reflect.MakeMap(mapType)
}
out.SetMapIndex(value, key)
}
}
return out
}
This code panic with error:
panic: reflect.Value.SetMapIndex: value of type int is not assignable to type reflect.Value
I think the reason of this error is the declaration of out variable, but I don't know how to declare it correctly, if I don't know the type of this variable.
How can I fix this error?
The key and value are of type reflect.Value, so passing them to reflect.TypeOf() will not return the type descriptors of the key and value types of the map (string and int), but instead the type descriptor of the reflect.Value type itself.
Instead simply call their Value.Type() method:
mapType := reflect.MapOf(value.Type(), key.Type())
With this it'll (almost) work and print (try it on the Go Playground):
map[1:one 2:two]
I wrote "almost" because you're returning a reflect.Value, not a map. But if a reflect.Value is passed to the fmt package, it prints the value wrapped inside it:
If the operand is a reflect.Value, the operand is replaced by the concrete value that it holds, and printing continues with the next rule.
So you should call Value.Interface() on out before returning it.
It's easier to return early if the kind is not map, so you can create the map right after that:
func ReverseMap(in interface{}) interface{} {
v := reflect.ValueOf(in)
if v.Kind() != reflect.Map {
return nil
}
mapType := reflect.MapOf(v.Type().Elem(), v.Type().Key())
out := reflect.MakeMap(mapType)
for _, key := range v.MapKeys() {
out.SetMapIndex(v.MapIndex(key), key)
}
return out.Interface()
}
Try this variant on the Go Playground.
Another approach may be using Value.MapRange():
for iter := v.MapRange(); iter.Next(); {
out.SetMapIndex(iter.Value(), iter.Key())
}
Try this variant on the Go Playground.

How to access struct field which is a pointer inside of a struct which is itself a pointer

In my code below, why does *bikeSlice[0].Type return to me the value of the Type field instead of the memory address? How come *bikeSlice[0] returns {Type:0xc0000641c0} though *bikeSlice[0].Type seems to automatically dereference the Type field?
package main
import "fmt"
type Bike struct {
Type *string
}
func main() {
type1 := "road"
bike1 := Bike{
Type: &type1,
}
type2 := "mountain"
bike2 := Bike{
Type: &type2,
}
var bikeSlice []*Bike
bikeSlice = append(bikeSlice, &bike1)
bikeSlice = append(bikeSlice, &bike2)
fmt.Printf("%+v\n", *bikeSlice[0])
fmt.Printf("%+v", *bikeSlice[0].Type)
}
Playground: https://play.golang.org/p/2Q4Bt60SUdW
Output:
{Type:0x40e128}
road
Yes I think it will automatically dereference. See https://golang.org/ref/spec#Selectors
I think rule number 3 is the one you're looking for:
As an exception, if the type of x is a defined pointer type and (*x).f is a valid selector expression denoting a field (but not a method), x.f is shorthand for (*x).f.

How to convert interface to struct

Here is the simplified code of a cache. Suppose Container placed in a package, so it don't know about Member.
While I wanna store instances of Member in Container, So I store an empty instance of Member in Container as outerType.
In the Container->GetMysql, I fill a new variable by test values (but, in real world, It fill by data of database, dynamically).
then in the function Put, I store data in items as Cache for next uses. In the Get I get the data stored in the items.
Before this every thing is fine. My problem is where i want to convert result of Get to type of Member m = res.(Member) . How Can I convert it to an instance of Member
I found many question about this subject, but none of them solved my problem
For more detail: I want the Get return data with its pointer of where it stored in items. So if I get some variable of same member, an change in one are shown in others
package main
import (
"fmt"
"reflect"
)
type Member struct {
Id int
Name string
Credit int
Age int
}
type Container struct {
outerType interface{}
items map[string]*interface{}
}
func (cls *Container)GetMysql(s string, a int64) interface{}{
obj := reflect.New(reflect.TypeOf(cls.outerType))
elem := obj.Elem()
//elem := reflect.ValueOf(o).Elem()
if elem.Kind() == reflect.Struct {
f := elem.FieldByName("Name")
f.SetString(s)
f = elem.FieldByName("Credit")
f.SetInt(a)
}
return obj.Interface()
}
func (cls *Container)Get(value string) *interface{}{
return cls.items[value]
}
func (cls *Container)Put(value string, a int64) {
res := cls.GetMysql(value, a)
cls.items[value] = &res
}
func main() {
c := Container{outerType:Member{}}
c.items = make(map[string]*interface{})
c.Put("Jack", 500)
res := c.Get("Jack")
fmt.Println(*res)
m := &Member{}
m = res.(Member) // Here is the problem. How to convert ?
fmt.Println(m)
}
You should hardly ever use pointer to interface. My advice is to never use it, when you'll need it, you'll know.
Instead if you need a pointer to something (so you can have the same pointer at multiple places, and so modifying the pointed value somewhere, it will have effect on the others), "wrap the pointer" in the interface value.
So first modify the items field so that it stores interface{} values instead of pointers:
items map[string]interface{}
This means no restriction: you can pass and store pointers, that's not a problem.
Next modify Get() to return interface{}:
func (cls *Container) Get(value string) interface{}{
return cls.items[value]
}
And also in Put(), don't take the address of an interface{}:
func (cls *Container) Put(value string, a int64) {
res := cls.GetMysql(value, a)
cls.items[value] = res
}
And you have to type-assert *Member from the values returned by Get().
And now testing it:
c := Container{outerType: Member{}}
c.items = make(map[string]interface{})
c.Put("Jack", 500)
res := c.Get("Jack")
fmt.Println(res)
m := res.(*Member) // Here is the problem. How to convert ?
fmt.Println(m)
Output (try it on the Go Playground):
&{0 Jack 500 0}
&{0 Jack 500 0}
Now if you would modify a field of m:
m.Credit = 11
And then get the value form the cache:
fmt.Println(c.Get("Jack"))
We'll see the modified value, even though we did not call Put() (try it on the Go Playground):
&{0 Jack 11 0}

Why int32(0) is not reflect.DeepEqual to type Zero in Golang?

I found this sort of validation in go-swagger package.
// Required validates an interface for requiredness
func Required(path, in string, data interface{}) *errors.Validation {
val := reflect.ValueOf(data)
if reflect.DeepEqual(reflect.Zero(val.Type()), val) {
return errors.Required(path, in)
}
return nil
}
I tried to use it and it forced me for some thoughts.
Why the following is not a true statement?
exper := int32(0)
reflect.DeepEqual(
reflect.Zero(reflect.ValueOf(exper).Type()),
reflect.ValueOf(exper)
)
Please check the godocs of reflect.Value:
Using == on two Values does not compare the underlying values they
represent, but rather the contents of the Value structs. To compare
two Values, compare the results of the Interface method.
Play
package main
import "reflect"
func main() {
//var i int32
exper := int32(0)
r := reflect.DeepEqual(
reflect.Zero(reflect.ValueOf(exper).Type()).Interface(),
reflect.ValueOf(exper).Interface(),
)
println(r) // true
}

Obtaining reflect.Ptr type to field in a Go struct

I am trying to pass to a third-party package a variadic list of pointers to fields in a struct. The package accepts a variadic interface{} list ( func Persist(...interface) error ), where each of the interface values is a pointer to a variable. I created a function that mocks how the third-party library and prints out the Type and Kind of the pointers (called mockFunction below).
When I pass it the address of the struct variables in a non-variadic way, they have their primitive Types and Values within the mocked function using the reflect calls. However, when I pass them in a variadic way using expansion, they have Type: Type: reflect.Value and Kind: struct. The third-party package does not know how to handle them in this form.
I would like to figure out a way to call the third-party package with a slice of interface{} (e.g. inv := make([]interface{}, 3) and use variadic expansion on the call Persist(inv...) if at all possible.
Here is the code with a link to Go Playground below:
package main
import (
"fmt"
"reflect"
)
type Investment struct {
Price float64
Symbol string
Rating int64
}
func main() {
inv := Investment{Price: 534.432, Symbol: "GBG", Rating: 4}
s := reflect.ValueOf(&inv).Elem()
variableParms := make([]interface{}, s.NumField())
for i := 0; i < s.NumField(); i++ {
variableParms[i] = s.Field(i).Addr()
}
// non-variadic call
mockFunction(&inv.Price, &inv.Symbol, &inv.Rating)
//variadic call
mockFunction(variableParms...)
}
func mockFunction(values ...interface{}) {
for i, value := range values {
rv := reflect.ValueOf(value)
fmt.Printf("value %d has Type: %s and Kind %s\n", i, rv.Type(), rv.Kind())
}
}
Go Playground Link
When I run it with the non-variadic parameters, the call to mockFunction returns the native Types and Kinds and the third-party package processes them fine:
value 0 has Type: *float64 and Kind ptr
value 1 has Type: *string and Kind ptr
value 2 has Type: *int64 and Kind ptr
When I run it with the variadic parameters, the values are different and the third-party package does not know how to handle these types:
value 0 has Type: reflect.Value and Kind struct
value 1 has Type: reflect.Value and Kind struct
value 2 has Type: reflect.Value and Kind struct
Is there any way to structure the slice definition and the call to what is placed in to the slice so that it can be variadic expanded and look like passing the pointers to the struct fields in the non-variadic way?
Addr() returns the reflect Value for the field pointer. Call Ptr() on the value to get the actual pointer as an interface{}.
variableParms[i] = s.Field(i).Addr().Ptr()
playground
I think that perhaps Go's handling for this case has changed since 2014 - certainly the code above no longer works for me with Go 1.10...
However the following code works for me to create an appropriate []interface{} to use in the described way...
func settableSliceFromStruct(inStruct interface{}) ([]interface{}, error) {
t := reflect.TypeOf(inStruct)
if t.Kind() != reflect.Ptr {
return nil, errors.New("can only assign values with pointer to struct")
}
v := reflect.ValueOf(inStruct).Elem()
t = t.Elem()
dataColumns := make([]interface{}, 0, t.NumField())
for i := 0; i < t.NumField(); i++ {
if weWantToIncludeThis(t.Field(i)) {
dataColumns = append(dataColumns, v.Field(i).Addr().Interface())
}
}
return dataColumns, nil
}
The critical part here would be for your code to use:
variableParms[i] = s.Field(i).Addr().Interface()

Resources