Print the key/value types of a Golang map - go

I am trying to print the type of a map, eg: map[int]string
func handleMap(m reflect.Value) string {
keys := m.MapKeys()
n := len(keys)
keyType := reflect.ValueOf(keys).Type().Elem().String()
valType := m.Type().Elem().String()
return fmt.Sprintf("map[%s]%s>", keyType, valType)
}
so if I do:
log.Println(handleMap(make(map[int]string)))
I want to get "map[int]string"
but I can't figure out the right calls to make.

func handleMap(m interface{}) string {
return fmt.Sprintf("%T", m)
}

Try not to use reflect. But if you must use reflect:
A reflect.Value value has a Type() function, which returns a reflect.Type value.
If that type's Kind() is reflect.Map, that reflect.Value is a value of type map[T1]T2 for some types T1 and T2, where T1 is the key type and T2 is the element type.
Therefore, when using reflect, we can pull apart the pieces like this:
func show(m reflect.Value) {
t := m.Type()
if t.Kind() != reflect.Map {
panic("not a map")
}
kt := t.Key()
et := t.Elem()
fmt.Printf("m = map from %s to %s\n", kt, et)
}
See a more complete example on the Go Playground. (Note that both maps are actually nil, so there are no keys and values to enumerate.)

Related

Extracting Generic Struct Values by Reflection

I'm trying to extract all of the values for a struct into a string slice.
func structValues(item Item) []string {
values := []string{}
e := reflect.ValueOf(&item).Elem()
for i := 0; i < e.NumField(); i++ {
fieldValue := e.Field(i).Interface()
values = append(values, fmt.Sprintf("%#v", fieldValue))
}
return values
}
I'd like to use this function with any struct, so I thought I could just change the type signature to func structValues(item interface{}) but then I got a panic:
panic: reflect: call of reflect.Value.NumField on interface Value
Working example: https://repl.it/#fny/stackoverflow61719532
I'd like to use this function with any struct ...
You can do this, but note that it gives up type-safety. Moreover, the only way to do this is to allow a call with any type, not just any type that is some structure type, so you have to check that what you got was in fact some struct type:
func structValues(item interface{}) {
if reflect.ValueOf(item).Kind() != reflect.Struct {
... do something here ...
}
Having made that check—or deferring it slightly, or omitting it to allow reflect to panic instead—you then need to replace reflect.ValueOf(&item).Elem() with the simpler reflect.ValueOf(item).
If you wish to allow pointers to structures as well as actual structures, you can make that happen pretty simply by using reflect.Indirect first. The result is:
func structValues(item interface{}) []string {
e := reflect.Indirect(reflect.ValueOf(item))
if e.Kind() != reflect.Struct {
panic("not a struct")
}
values := []string{}
for i := 0; i < e.NumField(); i++ {
fieldValue := e.Field(i).Interface()
values = append(values, fmt.Sprintf("%#v", fieldValue))
}
return values
}
Leave out the reflect.Indirect if you want to make sure that callers do their own indirection when they have a pointer.
(Note that the panic here is not very friendly. If you want proper debugging, consider either just printing the struct directly with %v or %#v, or for something much more thorough, the spew package.)
Complete example here on the Go Playground uses your type Item struct from your own link.

Go: A function that would consume maps with different types of values

In my code, I need a function that would return an ordered slice of keys from a map.
m1 := make(map[string]string)
m2 := make(map[string]int)
And now I need to call a function passing both types of maps:
keys1 := sortedKeys(m1)
keys2 := sortedKeys(m1)
Problem: I have to write two functions because the function should consume maps of two different types. At the same time, the body of the function will be the same in both cases.
Question: How can I use a single implementation for two maps? Or is there any other way of solving the problem in an elegant way?
My first idea was to use map[string]interface{} as an argument type, but you can't assign neither map[string]string, nor map[string]int to it.
My code:
func sortedKeys(m map[string]string) []string {
var keys []string
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
I would have to repeat the same code but for map[string]int.
You can use interface{} and use reflection for achieving this.
You can write two functions for the same but it is just not scalable, say, you are supporting string and int now but you wish to support int64, float64, bool or struct in the future. Having a common function using map[string]interface{} and using reflection is the way to go.
Suggested Code :
package main
import (
"fmt"
"reflect"
)
func main() {
m1 := make(map[string]string)
m2 := make(map[string]int)
m1["a"] = "b"
m1["b"] = "c"
m2["a"] = 1
m2["b"] = 2
fmt.Println(sortedKeys(m1))
fmt.Println(sortedKeys(m2))
}
// Returns slice of values in the type which is sent to it
func sortedKeys(m interface{}) interface{} {
if m == nil {
return nil
}
if reflect.TypeOf(m).Kind() != reflect.Map {
return nil
}
mapIter := reflect.ValueOf(m).MapRange()
mapVal := reflect.ValueOf(m).Interface()
typ := reflect.TypeOf(mapVal).Elem()
outputSlice := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0)
for mapIter.Next() {
outputSlice = reflect.Append(outputSlice, mapIter.Value())
}
return outputSlice.Interface()
}
Output :
[b c]
[1 2]
https://play.golang.org/p/2fkpydH9idG

How to create type conditionals for functions that accept interface{} in go?

I'm writing a function that is meant to accept either strings or slices in go. However, when I type my parameters as interface{} I can't perform actions upon those variables even when inside a conditional which checks the type.
Can the compiler deduce that my local variable must be of type Slice once inside my if block? How can I accomplish a for loop over the Slice after I know for certain it is a Slice?
func createFields(keys interface{}, values interface{}) ([]map[string]interface{}, error) {
fields := make([]map[string]interface{}, 1, 1)
if reflect.TypeOf(keys).Kind() == reflect.Slice && reflect.TypeOf(values).Kind() == reflect.Slice {
if len(keys.([]interface{})) != len(values.([]interface{})) {
return fields, errors.New("The number of keys and values must match")
}
// How can I loop over this slice inside the if block?
for i, key := range keys.([]interface{}) {
item := map[string]string{
"fieldID": keys[i], // ERROR: invalid operation: keys[i] (type interface {} does not support indexing)
"fieldValue": values[i],
}
fields.append(item)// ERROR: fields.append undefined (type []map[string]interface {} has no field or method append)
}
return fields, _
}
if reflect.TypeOf(keys).Kind() == reflect.String && reflect.Typeof(values).Kind() == reflect.String {
item := map[string]string{
"fieldID": keys,
"fieldValue": values,
}
fields.append(item)
return fields, _
}
return fields, errors.New("Parameter types did not match")
}
Use type assertions like
keySlice := keys.([]interface{})
valSlice := values.([]interface{})
and work with those from that point onwards. You can even eliminate the use of reflect, like:
keySlice, keysIsSlice := keys.([]interface{})
valSlice, valuesIsSlice := values.([]interface{})
if (keysIsSlice && valuesIsSlice) {
// work with keySlice, valSlice
return
}
keyString, keysIsString := keys.(string)
valString, valuesIsString := values.(string)
if (keysIsString && valuesIsString) {
// work with keyString, valString
return
}
return errors.New("types don't match")
Or you can structure the whole thing as type switches:
switch k := keys.(type) {
case []interface{}:
switch v := values.(type) {
case []interface{}:
// work with k and v as slices
default:
// mismatch error
}
case string:
switch v := values.(type) {
case string:
// work with k and v as strings
default:
// mismatch error
}
default:
// unknown types error
}

Get all fields from an interface

How do I know the fields I can access from the reply object/interface? I tried reflection but it seems you have to know the field name first. What if I need to know all the fields available to me?
// Do sends a command to the server and returns the received reply.
Do(commandName string, args ...interface{}) (reply interface{}, err error)
You can use the reflect.TypeOf() function to obtain a reflect.Type type descriptor. From there, you can list fields of the dynamic value stored in the interface.
Example:
type Point struct {
X int
Y int
}
var reply interface{} = Point{1, 2}
t := reflect.TypeOf(reply)
for i := 0; i < t.NumField(); i++ {
fmt.Printf("%+v\n", t.Field(i))
}
Output:
{Name:X PkgPath: Type:int Tag: Offset:0 Index:[0] Anonymous:false}
{Name:Y PkgPath: Type:int Tag: Offset:4 Index:[1] Anonymous:false}
The result of a Type.Field() call is a reflect.StructField value which is a struct, containing the name of the field among other things:
type StructField struct {
// Name is the field name.
Name string
// ...
}
If you also want the values of the fields, you may use reflect.ValueOf() to obtain a reflect.Value(), and then you may use Value.Field() or Value.FieldByName():
v := reflect.ValueOf(reply)
for i := 0; i < v.NumField(); i++ {
fmt.Println(v.Field(i))
}
Output:
1
2
Try it on the Go Playground.
Note: often a pointer to struct is wrapped in an interface. In such cases you may use Type.Elem() and Value.Elem() to "navigate" to the pointed type or value:
t := reflect.TypeOf(reply).Elem()
v := reflect.ValueOf(reply).Elem()
If you don't know whether it's a pointer or not, you can check it with Type.Kind() and Value.Kind(), comparing the result with reflect.Ptr:
t := reflect.TypeOf(reply)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
// ...
v := reflect.ValueOf(reply)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
Try this variant on the Go Playground.
For a detailed introduction to Go's reflection, read the blog post: The Laws of Reflection.

interface{} variable to []interface{}

I have an interface{} variable and I know it's a pointer to slice:
func isPointerToSlice(val interface{}) bool {
value := reflect.ValueOf(val)
return value.Kind() == reflect.Ptr && value.Elem().Kind() == reflect.Slice
}
But I'm finding difficult to type cast it into an []interface{} variable:
if isPointerToSlice(val) {
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
// 'worked' is false :(
}
This doesn't work. Any idea how can I solve this?
If you just want to convert a slice to []interface{} you can use something like this:
func sliceToIfaceSlice(val interface{}) []interface{} {
rf := reflect.Indirect(reflect.ValueOf(val)) // skip the pointer
if k := rf.Kind(); k != reflect.Slice && k != reflect.Array {
// panic("expected a slice or array")
return nil
}
out := make([]interface{}, rf.Len())
for i := range out {
out[i] = rf.Index(i).Interface()
}
return out
}
playground
You can simply use type assertion to obtain the value stored in an interface, e.g.
if isPointerToSlice(val) {
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
} else {
fmt.Println("Not *[]interface{}")
}
The type of the value stored in the interface as you claim is pointer to []interface{}, which is *[]interface{}. The result of the type assertion will be a pointer, just dereference it to get the slice []interface{}.
Using short variable declaration:
result := *val.(*[]interface{}) // type of result is []interface{}
Try it on the Go Playground.
Also your attempt also works:
slice, worked := reflect.ValueOf(val).Elem().Interface().([]interface{})
fmt.Println(slice, worked)
Here's the edited the Playground example which proves your solution works.
But using reflection is unnecessary (as it can be done with type assertion).
Also note that *[]interface{} and *[]someOtherType are 2 different types and you can't obtain a value of *[]interface{} if there is something else in val.
Icza's answer is great and will work especially if you can't know for sure you are getting an interface slice, however if you don't want to bother with the reflect package at all and want to keep imported code low, you can use type switching to obtain the same functionality using only built-in methods.
Using this method, you can shorten your code to just:
package main
import (
"fmt"
)
func main() {
s := []interface{}{"one", 2}
p := &s
do(p)
}
func do(val interface{}) {
switch val.(type){
case *[]interface{}:
var result []interface{}
result = *val.(*[]interface{})
fmt.Println(result)
}
}
Playground: http://play.golang.org/p/DT_hb8JcVt
The downside is if you don't know the exact type of slice you are receiving beforehand, then this will not work unless you list all possible types for handling and assertion.

Resources