Using recursion to get the deeply nested struct in go - recursion

I need to parse an interface read from a JSON object which is deeply nested. I use the following recursive function to get most of the array.
func arrayReturn(m map[string]interface{}) []interface{} {
for _, v:= range m {
if v.(type) == map[string]interface{} {
return arrayReturn(v.(map[string]interface{}))
}
if v.(type) == string {
return v.([]interface{})
}
}
}
Which gives this error for the return line:
syntax error: unexpected return, expecting expression
What does "expecting expression" mean?

This syntax:
if v.(type) == map[string]interface{} { /* ... */ }
is invalid. You can't compare to a type, only to a value.
What you want may be solved using a type switch, where the cases are indeed types:
func arrayReturn(m map[string]interface{}) []interface{} {
for _, v := range m {
switch v2 := v.(type) {
case map[string]interface{}:
return arrayReturn(v2) // v2 is of type map[string]interface{}
case []interface{}:
return v2 // v2 is of type []interface{}
}
}
return nil
}
Also note that if you use a short variable declaration after the switch keyword, in each case the type of the variable used will be what you specify in the case, so no further type assertion is needed!

Related

Unable to retain values of golang fields when its returned to the caller of the function

I have a function which accepts slice of values and fields as a set of optional parameters and the function maps each value to a field and returns error if any to the caller as in below
func Unmarshall(source []interface{}, dest ...interface{}) error {
if len(source) != len(dest) {
return errors.New("source and destination doesn't match")
}
for i, s := range source {
dest[i] = s
}
return nil
}
and below the code I have for the caller
for _, r := range rows.Values {
item := entity.Item{}
e :=Unmarshall(r,
&item.Name,
&item.Description,
&item.AddedUTCDatetime,
&item.ModifiedUTCDatetime)
if e == nil {
items = append(items, item)
}
}
But the issue with the above is item.Name,item.Description, &item.AddedUTCDatetime, &item.ModifiedUTCDatetime doesn't retain the values set in the Unmarshall func even though I passed in the pointer to the fields.
Is there anything wrong with the above code?
Is there anything wrong with the above code?
Yes. You're discarding the pointers and are simply overwriting them with new values. To set value that pointer points to, you must dereference it. Could look something like this in your case:
for i, s := range source {
str, ok := dest[i].(*string)
if ok {
*str = s.(string)
}
}
This one takes care of all types
for i, s := range source {
so := reflect.ValueOf(s)
if !reflect.DeepEqual(so, reflect.Zero(reflect.TypeOf(so)).Interface()) {
reflect.ValueOf(dest[i]).Elem().Set(so)
}
}

How to set an interface{} parameter by reference?

I have a function that has a parameter with the type interface{}. This parameter represents my template data. So on each page it stores different data types (mostly structs). I want to append some data to this parameter's data, but it's an interface{} type and I can't do it.
This is what I tried:
func LoadTemplate(templateData interface) {
appendCustomData(&templateData)
... //other functionality that is not relevant
}
func appendCustomData(dst interface{}) {
// ValueOf to enter reflect-land
dstPtrValue := reflect.ValueOf(dst)
// need the type to create a value
dstPtrType := dstPtrValue.Type()
// *T -> T, crashes if not a ptr
dstType := dstPtrType.Elem()
// the *dst in *dst = zero
dstValue := reflect.Indirect(dstPtrValue)
// the zero in *dst = zero
zeroValue := reflect.Zero(dstType)
// the = in *dst = 0
v := reflect.ValueOf(dst).Elem().Elem().FieldByName("HeaderCSS")
if v.IsValid() {
v = reflect.ValueOf("new header css value")
}
reflect.ValueOf(dst).Elem().Elem().FieldByName("HeaderCSS").Set(reflect.ValueOf(v))
//dstValue.Set(zeroValue)
fmt.Println("new dstValue: ", dstValue)
}
I can successfully get the "HeaderCSS" value. But I can't replace it with another value. What am I doing wrong?
My templateData looks like this:
I have a generic struct:
type TemplateData struct {
FooterJS template.HTML
HeaderJS template.HTML
HeaderCSS template.HTML
//and some more
}
and I have another struct, such as:
type pageStruct struct {
TemplateData //extends the previous struct
Form template.HTML
// and some other maps/string
}
I send this second struct as templateData argument.
Right now I get this error:
"reflect.Value.Set using unaddressable value" at the line: reflect.ValueOf(dst).Elem().Elem().FieldByName("HeaderCSS").Set(reflect.ValueOf(v))
The code from above is inspired from this answer: https://stackoverflow.com/a/26824071/1564840
I want to be able to append/edit values from this interface. Any idea how can I do it? Thanks.
Don't pass a pointer to interface. Instead the interface{} value should contain the pointer. And simply just hand over this interface{} value:
func LoadTemplate(templateData interface) {
appendCustomData(templateData)
... //other functionality that is not relevant
}
Even if you can't use a more concrete type than interface{} (because you must allow multiple types), you can still use type assertion, it will be "super" easy:
func appendCustomData(d interface{}) {
if ps, ok := d.(*pageStruct); ok {
ps.TemplateData.HeaderCSS += "+new"
}
}
Try this one on the Go Playground.
If you must or want to use reflection, this is how appendCustomData() can be implemented:
type Data struct {
Name string
Age int
Marks []int
}
func appendCustomData(d interface{}) {
v := reflect.ValueOf(d).Elem()
if f := v.FieldByName("Name"); f.IsValid() {
f.SetString(f.Interface().(string) + "2")
}
if f := v.FieldByName("Age"); f.IsValid() {
f.SetInt(f.Int() + 2)
}
if f := v.FieldByName("Marks"); f.IsValid() {
f.Set(reflect.ValueOf(append(f.Interface().([]int), 2)))
}
if f := v.FieldByName("Invalid"); f.IsValid() {
f.Set(reflect.ValueOf(append(f.Interface().([]int), 2)))
}
}
Testing it:
d := &Data{
Name: "Bob",
Age: 22,
Marks: []int{5, 4, 3},
}
fmt.Printf("%+v\n", d)
appendCustomData(d)
fmt.Printf("%+v\n", d)
Output (try it on the Go Playground):
&{Name:Bob Age:22 Marks:[5 4 3]}
&{Name:Bob2 Age:24 Marks:[5 4 3 2]}
Update:
To answer your edited question: there is no difference when the value passed is a struct that embeds another struct. But the value wrapped in the interface{} still must be a pointer.
Example appendCustomData() that appends content to pageStruct.TemplateData.HeaderCSS:
func appendCustomData(d interface{}) {
v := reflect.ValueOf(d).Elem()
if f := v.FieldByName("TemplateData"); f.IsValid() {
if f = f.FieldByName("HeaderCSS"); f.IsValid() {
f.Set(reflect.ValueOf(f.Interface().(template.HTML) + "+new"))
}
}
}
Testing it:
ps := &pageStruct{
TemplateData: TemplateData{
HeaderCSS: template.HTML("old"),
},
}
fmt.Printf("%+v\n", ps)
appendCustomData(ps)
fmt.Printf("%+v\n", ps)
Output (try it on the Go Playground):
&{TemplateData:{FooterJS: HeaderJS: HeaderCSS:old} Form:}
&{TemplateData:{FooterJS: HeaderJS: HeaderCSS:old+new} Form:}

How to get a pointer to a variable that's masked as an interface?

I prefer not to dive into the rationale of the situation below. It has to do with unmarshaling an serialized object that can be any of a fixed set of types, but you don't know which type.
I have the following types:
type I interface {
Do()
}
type someI struct {}
func (i *someI) Do() {}
type otherI struct {}
func (i *otherI) Do() {}
So, two structs of which the pointers implement interface I.
Now I have this method that wants to return a value of type I:
func GetSomeI(marshalled []byte) (I, error) {
var obj interface{}
// The following method magically puts an instance
// of either someI or otherI into obj.
magicUnmarshall(marshalled, obj)
// The problem now is that we cannot return obj,
// because the raw structs don't implement I.
// One solution would be to do a type switch like this:
switch obj.(type) {
case someI:
i := obj.(someI)
return &i, nil
case otherI:
i := obj.(otherI)
return &i, nil
default:
return nil, errors.New("marschalled object was not of type I")
}
// But now consider the case that there are quite some
// different implementations of I.
// We would prefer to have a general way of getting
// a reference to obj.
}
To tell if a value wrapped in an interface{} implements some other interface (I), you may simply use a type assertion.
Note that you must pass the address of the variable you want results unmarshaled to.
For demonstration purposes, let's use the following magicUnmarshal() function:
func magicUnmarshal(what int, obj interface{}) {
v := reflect.ValueOf(obj).Elem()
switch what {
case 0:
v.Set(reflect.ValueOf(&someI{}))
case 1:
v.Set(reflect.ValueOf(&otherI{}))
case 2:
v.Set(reflect.ValueOf("just a string"))
case 3:
v.Set(reflect.ValueOf(someI{}))
case 4:
v.Set(reflect.ValueOf(otherI{}))
}
}
Note that case 3 and case 4 are returning non-pointers.
Your GetSomeI() implementation can be:
func GetSomeI(what int) (I, error) {
var obj interface{}
magicUnmarshal(what, &obj)
// Try the value as-is:
if i, ok := obj.(I); ok {
return i, nil
}
// No success. Try a pointer to the value:
v := reflect.Indirect(reflect.New(reflect.TypeOf(obj)))
v.Set(reflect.ValueOf(obj))
pobj := v.Addr().Interface()
if i, ok := pobj.(I); ok {
return i, nil
}
return nil, fmt.Errorf("%T does not implement I!", obj)
}
First GeSomeI() tests if the value got form magicUnmarshal() implements I, and if so, it is used as-is. If not, we construct a new using reflection, and get its address (a pointer to a value), and we test that. If that pointer implements I, we return it.
Testing it:
func main() {
for what := 0; what < 5; what++ {
i, err := GetSomeI(what)
fmt.Printf("%T %v\n", i, err)
}
}
And the output is (try it on the Go Playground):
*main.someI <nil>
*main.otherI <nil>
<nil> string does not implement I!
*main.someI <nil>
*main.otherI <nil>

Passing values to interface{}

Short
The following code does not exactly do what expected:
https://play.golang.org/p/sO4w4I_Lle
I assume that I mess up some pointer/reference stuff as usual, however I expect my...
func unmarshalJSON(in []byte, s interface{}) error
... and encoding/jsons...
func Unmarshal(data []byte, v interface{}) error
...to behave the same way (eg. update the referenced passed as second argument).
Long
The example above is a minimal reproducer that does not make much sense. This is in order to make it work on the playground. However, an less minimal example that does make sense is this:
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
func unmarshalYAML(in []byte, s interface{}) error {
var result map[interface{}]interface{}
err := yaml.Unmarshal(in, &result)
s = cleanUpInterfaceMap(result)
// s is printed as expected
fmt.Println(s) // map[aoeu:[test aoeu] oaeu:[map[mahl:aoec tase:aoeu]]]
return err
}
func cleanUpInterfaceArray(in []interface{}) []interface{} {
out := make([]interface{}, len(in))
for i, v := range in {
out[i] = cleanUpMapValue(v)
}
return out
}
func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
out := make(map[string]interface{})
for k, v := range in {
out[fmt.Sprintf("%v", k)] = cleanUpMapValue(v)
}
return out
}
func cleanUpMapValue(v interface{}) interface{} {
switch v := v.(type) {
case []interface{}:
return cleanUpInterfaceArray(v)
case map[interface{}]interface{}:
return cleanUpInterfaceMap(v)
case string:
return v
default:
return fmt.Sprintf("%v", v)
}
}
func main() {
s := make(map[string]interface{})
b := []byte(`---
aoeu:
- test
- aoeu
oaeu:
- { tase: aoeu, mahl: aoec}
`)
err := unmarshalYAML(b, &s)
if err != nil {
panic(err)
}
// s is still an empty map
fmt.Println(s) // map[]
}
The idea is to unmarshal YAML to map[string]interface{} (instead of map[interface{}]interface{}) is order to allow to serialize to JSON (where identifiers need to be strings). The unmarshalYAML function should provide the same func signture as yaml.Unmarshal...
Using Type assertion
Inside your unmarshalJSON() function the parameter s behaves like a local variable. When you assign something to it:
s = result
It will only change the value of the local variable.
Since you want it to work with changing the value of a *map[string]interface{} and that is what you pass to it, you could use a simple type assertion to obtain the map pointer from it, and pass this pointer to json.Unmarshal():
func unmarshalJSON(in []byte, s interface{}) error {
if m, ok := s.(*map[string]interface{}); !ok {
return errors.New("Expecting *map[string]interface{}")
} else {
return json.Unmarshal(in, m)
}
}
Try your modified, working example on the Go Playground.
Just passing it along
Also note that however this is completely unnecessary as json.Unmarshal() is also defined to take the destination as a value of type interface{}, the same thing you have. So you don't even have to do anything just pass it along:
func unmarshalJSON(in []byte, s interface{}) error {
return json.Unmarshal(in, s)
}
Try this on the Go Playground.
With a variable of function type
As an interesting thing note that the signature of your unmarshalJSON() and the library function json.Unmarshal() is identical:
// Yours:
func unmarshalJSON(in []byte, s interface{}) error
// json package
func Unmarshal(data []byte, v interface{}) error
This means there is another option, that is you could use a variable named unmarshalJSON of a function type, and just simply assign the function value json.Unmarshal:
var unmarshalJSON func([]byte, interface{}) error = json.Unmarshal
Now you have a variable unmarshalJSON which is of function type, and you can call it as if it would be a function:
err := unmarshalJSON(b, &s)
Try this function value on the Go Playground.
Now on to your unmarshalYAML() function
In your unmarshalYAML() you do the same mistake:
s = cleanUpInterfaceMap(result)
This will only change the value of your local s variable (parameter), and it will not "populate" the map (pointer) passed to unmarshalYAML().
Use the type assertion technique detailed above to obtain the pointer from the s interface{} argument, and once you have that, you can change the pointed object (the "outside" map).
func unmarshalYAML(in []byte, s interface{}) error {
var dest *map[string]interface{}
var ok bool
if dest, ok = s.(*map[string]interface{}); !ok {
return errors.New("Expecting *map[string]interface{}")
}
var result map[interface{}]interface{}
if err := yaml.Unmarshal(in, &result); err != nil {
return err
}
m := cleanUpInterfaceMap(result)
// m holds the results, dest is the pointer that was passed to us,
// we can just set the pointed object (map):
*dest = m
return nil
}

Discover the return type of the current function in go

I have a function that is being generated using reflection and reflect.MakeFunc, so I don't actually have the return type until runtime.
Inside the template function that MakeFunc is using, is there a way to determine the return type of the concrete function being templated?
Essentially, is there a way to determine the return type iof the currently executing function at runtime?
I know about the Out method:
fn.Type().Out(0)
And I can find the return type of a function easily enough?
But is there a way to find the return type of the currently executing function (as opposed to an explicit passed function reference).
You should check fn.Type().Out(0).Kind(), for example:
func main() {
fnTmpl := func(in []reflect.Value) []reflect.Value {
return []reflect.Value{in[0]}
}
makeFn := func(fptr interface{}) {
fn := reflect.ValueOf(fptr).Elem()
fn.Set(reflect.MakeFunc(fn.Type(), fnTmpl))
}
var nFn func(int) int
makeFn(&nFn)
kind := reflect.TypeOf(nFn).Out(0).Kind()
switch kind {
case reflect.Int:
fmt.Println("int")
}
}
In the case you are talking about, the return type of the currently executing function is always []reflect.Type (because that is what a function passed to reflect.MakeFunc must return). What you really want is the return type of the reflect.makeFuncStub function that called your function.
There is no way to get that (except perhaps some strange inspection of the call stack), but you can make an enhanced version of MakeFunc that provides the information:
package main
import (
"fmt"
"reflect"
)
// MakeFunc is like reflect.MakeFunc, but fn has an extra argument, retType, which
// is passed the desired return type.
func MakeFunc(typ reflect.Type, fn func(args []reflect.Value, retType reflect.Type) (results []reflect.Value)) reflect.Value {
if n := typ.NumOut(); n != 1 {
panic("wrong number of return values")
}
rt := typ.Out(0)
return reflect.MakeFunc(typ, func(args []reflect.Value) (results []reflect.Value) {
return fn(args, rt)
})
}
func makeReturnOne(fptr interface{}) {
fn := reflect.ValueOf(fptr).Elem()
fn.Set(MakeFunc(fn.Type(), returnOne))
}
func returnOne(args []reflect.Value, retType reflect.Type) []reflect.Value {
ret := reflect.New(retType).Elem()
switch retType.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
ret.SetInt(1)
case reflect.Float32, reflect.Float64:
ret.SetFloat(1.0)
default:
panic("returnOne only supports int and float types")
}
r := ret.Interface()
fmt.Printf("returning %v as %T\n", r, r)
return []reflect.Value{ret}
}
func main() {
var r1f func() float64
var r1i func() int
makeReturnOne(&r1f)
makeReturnOne(&r1i)
fmt.Println(r1f())
fmt.Println(r1i())
}
I might have misinterpreted what you are trying to achieve, but why not just take the kind of the value you are returning? Modifying OneOfOne's example as follows:
fnTmpl := func(in []reflect.Value) (res []reflect.Value) {
res = []reflect.Value{in[0]}
fmt.Println("Returned:", res[0].Kind())
return res
}
Playground: http://play.golang.org/p/EujmxyGRrI

Resources