How to cast interface{} to a map in GO - go

I am new to Go & I am trying to learn how to cast interface{} to a Map. Here is an example of what I am trying to implement.
Playground link : https://play.golang.org/p/3jhKlGKO46Z
Thanks for the help.
package main
import (
"fmt"
)
func main() {
Map := make(map[string]interface{})
test(Map)
for k,v := range Map {
fmt.Println("key : %v Value : %v", k, v)
}
}
func test(v interface{}) error{
data := make(map[int]interface{})
for i := 0; i < 10; i++ {
data[i] = i * 5
}
for key,val := range data {
// fmt.Println("key : %v Value : %v", key, val)
v[key] = val
}
return nil

Go supports type assertions for the interfaces. It provides the concrete value present in the interface.
You can achieve this with following code.
m, ok := v.(map[int]interface{})
if ok {
// use m
_ = m
}
If the asserted value is not of given type, ok will be false
If you avoid second return value, the program will panic for wrong assertions.
I strongly recommend you to go through https://tour.golang.org

Related

Instantiate a new obj using Go reflect and type assert to an interface

I can't explain why the following is working.
package main
import (
"fmt"
"reflect"
"strings"
)
type MyInterface interface {
someFunc()
}
type Dock struct {
}
func (d *Dock) someFunc() {
}
type Group struct {
Docks []Dock `better:"sometag"`
}
func foo(model interface{}) {
v1 := reflect.Indirect(reflect.ValueOf(model))
for i := 0; i < v1.NumField(); i++ {
tag := v1.Type().Field(i).Tag.Get("better")
if strings.HasPrefix(tag, "sometag") {
inter := v1.Field(i).Interface()
typ := reflect.TypeOf(inter).Elem()
fmt.Println("Type:", typ.String())
// Want to instantiate type like &Dock{} then assign it to some interface,
// but using reflect
n := reflect.New(typ)
_, ok := n.Interface().(MyInterface)
fmt.Println("Why is it OK?", ok)
}
}
}
func main() {
g := &Group{}
foo(g)
/*var v1, v2 interface{}
d1 := &Dock{}
v1 = d1
_, ok1 := v1.(MyInterface)
d2 := Dock{}
v2 = d2
_, ok2 := v2.(MyInterface)
fmt.Println(ok1, ok2)*/
}
It prints
Type: main.Dock
OK? true
If it's a Dock type, then it's not a pointer to Dock. Why does it conforms to MyInterface?
https://play.golang.org/p/Z9mR8amYOM7
Where as the d2 example in the comment does not.
In go doc for reflect.New
New returns a Value representing a pointer to a new zero value for the
specified type. That is, the returned Value's Type is PtrTo(typ).
n := reflect.New(typ)
fmt.Println("Type:", n.String())
It will print Type: <*main.Dock Value> means n is a pointer of Dock.You miss the part using reflect.New return the pointer.

Golang reflection MethodByName()

I write the code that fills data structures depending on its type. I need to call nested struct function if it exists.
Why I get zero value looking for function while the field is correct?
type (
SomeData struct {
Val NestedType
}
NestedType struct {
V1 string
}
)
func (t *NestedType) FillData(v int) {
t.V1 = fmt.Sprintf("Here is %v", v)
}
func main() {
i := SomeData{}
reflect.ValueOf(&i.Val).MethodByName("FillData").Call([]reflect.Value{reflect.ValueOf(555)})
fmt.Println(i) /// {{I hate 555}}
// BUT!
v := 666
newObj := reflect.New(reflect.TypeOf(SomeData{}))
fVal := newObj.Elem().FieldByName("Val")
fmt.Println( "fVal.NumField():", fVal.NumField()) //fVal.NumField(): 1
f := fVal.MethodByName("FillData")
f.Call([]reflect.Value{reflect.ValueOf(v)}) //panic: reflect: call of reflect.Value.Call on zero Value
}
The method is on the pointer receiver. The value fVal is a NestedType. Call Value.Addr to get a *NestedType:
f := fVal.Addr().MethodByName("FillData")
Run it on the playground.

How to convert interface to interfaces slice?

My input is an interface{}, and I know it can be an array of any type.
I'd like to read one of the elements of my input, so I try to convert my interface{} into an []interface{}, but go will give me the following error:
panic: interface conversion: interface {} is []map[string]int, not []interface {}
How can I do that conversion? (without reflect if possible).
Playground test
Thanks
The solution involving the reflect package.
package main
import (
"fmt"
"reflect"
)
func main() {
var v interface{} = []string{"a", "b", "c"}
var out []interface{}
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Slice {
for i := 0; i < rv.Len(); i++ {
out = append(out, rv.Index(i).Interface())
}
}
fmt.Println(out)
}
// Output:
// [a b c]
I'm actually working on this right now as my issue involves taking something from a json object (map[string]interface{}) which may or may not contain a particular key ({"someKey": [a, b, c, ...]) and if it does contain that key then we want to take that (which will necessarily be interface{} type) and convert it to []interface{}. The method I've found so far is to use json marshall/unmarshall. This seems a little hacky to me, will update if I find a more elegant solution. Til then, you can have my method:
https://play.golang.org/p/4VAwQQE4O0b
type a map[string]interface{}
type b []string
func main() {
obj := a{
"someKey": b{"a", "b", "c"},
}
if obj["someKey"] != nil { // check the value exists
var someArr []interface{}
//marshal interface to byte and then unmarshal to []interface{}
somebytes, _ := json.Marshal(obj["someKey"])
err := json.Unmarshal(somebytes, &someArr)
if err != nil {
fmt.Println("Error in unmarshal")
}
fmt.Println(someArr)
}
}
How can I do that conversion? (without reflect if possible).
Please consider type switches.
Reflection is expensive.
func toSlice(i interface{}) []interface{} {
var out []interface{}
switch v := i.(type) {
case []interface{}:
for x := 0; x < len(v); x++ {
out = append(out, v[x])
}
default:
fmt.Printf("invalid type: %T\n", v)
}
return out
}
The point of the interface is to define the behaviour you want to use, if you use an empty interface, you know nothing about the types in that slice.
If you want to print it, you can use println or printf with no conversion.
If you want to access it, and must allow any type, you can use reflect (slow and complex to use).
If you want to acess it, and use common behaviour/ data that you can define functions for, define an interface, e.g. :
type Doer interface {
Do() error
}
parentStruct := []Doer{...}
testStruct.Do()
If none of that works, wait for Go 2 and generics.
For anyone finding this in 2022, now that we have generics you can do it like this:
func convertSlice[T any](data []T) []interface{} {
output := make([]interface{}, len(data))
for idx, item := range data {
output[idx] = item
}
return output
}
I think what you are looking is type assertion
package main
import (
"fmt"
)
func main() {
parentStruct := map[string]interface{}{
"test": []map[string]int{
{"a": 1, "b": 2},
{"c": 3},
},
}
testStruct := parentStruct["test"].([]map[string]int)
fmt.Println(testStruct)
}
read this link: https://golang.org/ref/spec#Type_assertions
https://play.golang.org/p/81uL2hgrN3l

How to convert string from interface to []string in golang?

I'm parsing a JSON object which contains an array of strings :
var ii interface{}
json := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
err := json.Unmarshal([]byte(json), &ii)
if err != nil {
log.Fatal(err)
}
data := ii.(map[string]interface{})
fmt.Println(data["aString"]) // outputs: ["aaa_111" "bbb_222"]
I tried to convert data["aString"] to []string to be able to loop over it, but it fails :
test := []string(data["aString"]).([]string)
fmt.Println(test) // panic -> interface conversion:
// interface is string, not []string
How can I convert data["aString"] ?
edit:
I didn't express myself properly. If I print data, I have such map :
map[aString:["BBB-222","AAA-111"] whatever:ccc]
I want to loop over aString (to manipule each array entry). But I can't find how, because aString is type interface {} :
for i, v := range aString { // <-- fails
// ...
fmt.Println(i, v)
}
That's why I want to convert aString. I don't want to convert a string which looks like an array to an array.
I recommend you move away from this implementation in general. Your json may vary but you can easily use objects and avoid all this type unsafe nonsense.
Anyway, that conversion doesn't work because the types inside the slice are not string, they're also interface{}. You have to iterate the collection then do a type assertion on each item like so:
aInterface := data["aString"].([]interface{})
aString := make([]string, len(aInterface))
for i, v := range aInterface {
aString[i] = v.(string)
}
Is it what you need?
package main
import (
"fmt"
"encoding/json"
)
func main() {
js := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
a := make(map[string]interface{})
json.Unmarshal([]byte(js), &a)
for _, v := range a["aString"].([]interface{}) {
str := v.(string)
fmt.Println(str)
}
}
Check on Go Playground
For another approach, you can use a struct instead:
package main
import (
"encoding/json"
"fmt"
)
func main() {
s := []byte(`{"aString": ["aaa_111", "bbb_222"], "whatever":"ccc"}`)
var t struct {
Astring []string
Whatever string
}
json.Unmarshal(s, &t)
fmt.Printf("%+v\n", t) // {Astring:[aaa_111 bbb_222] Whatever:ccc}
}

Reading bytes into structs using reflection

I'm trying to write functions that will allow me to marshal/unmarshal simple structs into byte arrays. I've succeeded in writing Marshal, with help from the kind folks at #go-nuts, but I'm running into trouble writing Unmarshal.
// Unmarshal unpacks the binary data and stores it in the packet using
// reflection.
func Unmarshal(b []byte, t reflect.Type) (pkt interface{}, err error) {
buf := bytes.NewBuffer(b)
p := reflect.New(t)
v := reflect.ValueOf(p)
for i := 0; i < t.NumField(); i++ {
f := v.Field(i)
switch f.Kind() {
case reflect.String:
// length of string
var l int16
var e error
e = binary.Read(buf, binary.BigEndian, &l)
if e != nil {
err = e
return
}
// read length-of-string bytes from the buffer
raw := make([]byte, l)
_, e = buf.Read(raw)
if e != nil {
err = e
return
}
// convert the bytes to a string
f.SetString(bytes.NewBuffer(raw).String())
default:
e := binary.Read(buf, binary.BigEndian, f.Addr())
if e != nil {
err = e
return
}
}
}
pkt = p
return
}
The problem with the code above is that the call to f.Addr() near the end is apparently trying to get the address of an unaddressable value.
If there is an alternative solution, I would appreciate that as well. Either way, any help would be much appreciated.
Thanks!
I think you should use
v := p.Elem() // Get the value that 'p' points to
instead of
v := reflect.ValueOf(p)
Working example with lots of assumptions and a trivial data format:
package main
import (
"fmt"
"reflect"
"strconv"
)
// example marshalled format. lets say that marshalled data will have
// four bytes of a formatted floating point number followed by two more
// printable bytes.
type m42 []byte
// example struct we'd like to unmarshal into.
type packet struct {
S string // exported fields required for reflection
F float64
}
// example usage
func main() {
var p packet
if err := Unmarshal(m42("3.14Pi"), &p); err == nil {
fmt.Println(p)
} else {
fmt.Println(err)
}
}
func Unmarshal(data m42, structPtr interface{}) error {
vp := reflect.ValueOf(structPtr)
ve := vp.Elem() // settable struct Value
vt := ve.Type() // type info for struct
nStructFields := ve.NumField()
for i := 0; i < nStructFields; i++ {
fv := ve.Field(i) // settable field Value
sf := vt.Field(i) // StructField type information
// struct field name indicates which m42 field to unmarshal.
switch sf.Name {
case "S":
fv.SetString(string(data[4:6]))
case "F":
s := string(data[0:4])
if n, err := strconv.ParseFloat(s, 64); err == nil {
fv.SetFloat(n)
} else {
return err
}
}
}
return nil
}
Appropriate alternative solutions would depend heavily on the real data you need to support.
I'm going to bet that the reason f.Addr() has the problem because it actually isn't addressable.
the reflect package Type object has a method that will tell you if the type is addressable called CanAddr(). Assuming the field is addressable if it's not a string is not always true. If the struct is not passed in as a pointer to a struct then it's fields won't be addressable. For more details about what is and isn't addressable see: http://weekly.golang.org/pkg/reflect/#Value.CanAddr which outlines the correct rules.
Essentially for your code to work I think you need to ensure you always call it with a pointer to a struct.

Resources