How to get a value from map - go

Problem
Fetching data from map
Data Format
res = map[Event_dtmReleaseDate:2009-09-15 00:00:00 +0000 +00:00 Trans_strGuestList:<nil> strID:TSTB]
Note
How to get the following value from the above result
Event_dtmReleaseDate
strID
Trans_strGuestList
What i tried:
res.Map("Event_dtmReleaseDate");
Error : res.Map undefined (type map[string]interface {} has no field or method Map)
res.Event_dtmReleaseDate;
Error: v.id undefined (type map[string]interface {} has no field or method id)

Your variable is a map[string]interface {} which means the key is a string but the value can be anything. In general the way to access this is:
mvVar := myMap[key].(VariableType)
Or in the case of a string value:
id := res["strID"].(string)
Note that this will panic if the type is not correct or the key does not exist in the map, but I suggest you read more about Go maps and type assertions.
Read about maps here: http://golang.org/doc/effective_go.html#maps
And about type assertions and interface conversions here: http://golang.org/doc/effective_go.html#interface_conversions
The safe way to do it without a chance to panic is something like this:
var id string
var ok bool
if x, found := res["strID"]; found {
if id, ok = x.(string); !ok {
//do whatever you want to handle errors - this means this wasn't a string
}
} else {
//handle error - the map didn't contain this key
}

In general to get value from map you have to do something like this:
package main
import "fmt"
func main() {
m := map[string]string{"foo": "bar"}
value, exists := m["foo"]
// In case when key is not present in map variable exists will be false.
fmt.Printf("key exists in map: %t, value: %v \n", exists, value)
}
Result will be:
key exists in map: true, value: bar

Related

assert interface{} to int64

i am using gin, i use c.shouldBind to bind the data to the struct, the use c.set to set the params in the context. when i use c.getInt64 to get the params, it can't return the value i set in the context(i set a 1), it return a zero. it failed to assert a float64 1 to a int64 0.
i have google it but can't get the answer i want
here are my debug code
// GetInt64 returns the value associated with the key as an integer.
func (c *Context) GetInt64(key string) (i64 int64) {
if val, ok := c.Get(key); ok && val != nil {
i64, _ = val.(int64)
}
return
}
the val is 1, but it returns 0
So can anybody tell me why and how to solve it.
Golang can't convert types implicitly. You can use the GetFloat64 method.
It depends the value which you really set in, and check the key is right, After that, Maybe you could use assertion after Get like: value := c.Get("From_validator_page").(Int64)

How to return key's value of a map of type empty interface

I have taken a variable like var u = make(map[string]interface{}) which means that a key could hold a string/int or another map.
When I do the following it gives error cannot use v (type interface {}) as type string in return argument: need type assertion which looks obvious as the generic map have no idea what should it search. How can I resolve the issue? The code is given below(DO note that currently, the map is entirely empty)
var u = make(map[string]interface{})
// Get function retrieves the value of the given key. If failed, it returns error.
func Get(k string) (string, error) {
v, found := u[k]
println(reflect.Type(v))
if found {
v = u[k]
return v, nil
}
return v, errors.New(-1)
}
v, found := u[k] here v is interface{} type
But your function return type is (string, nil) where you are returning (v, nil) or (interface{}, nil).
interface{} can not convert into string automatically, need type assertion.
data, ok := v.(string)
You can return interface{} also and the consumer can decide which type it will converted.
I'm not sure what's your question. But you're getting this error because you are trying to return interface{} as concrete type string. If you want to return string, and you're sure that value of map is always string(then why are you using map[string]interface{} instead of map[string]string?) you can get underlying type of interface by using type assertion:
s, ok := v.(string)

Does type assertion change the value in go?

Go newbie here.
I have a map where the key arguments should be []string.
However, if I try to use the value directly arguments := m["arguments"] it doesn't seem to be the right type. When used later to append to another slice with arguments... I get Cannot use 'arguments' (type interface{}) as type []string.
I fixed this by chaning the assignment to a type check arguments, _ := m["arguments"].([]string). That works, but I'm not sure why. Is type assertion doing conversion as well?
The full example is below:
import (
"github.com/fatih/structs"
"strings"
)
var playbookKeyDict = map[string]string{
"Playbook": "",
"Limit" : "--limit",
"ExtraVars" : "--extra-vars",
}
type Playbook struct {
Playbook string `json:"playbook" xml:"playbook" form:"playbook" query:"playbook"`
Limit string `json:"limit" xml:"limit" form:"limit" query:"limit"`
ExtraVars string `json:"extra-vars" xml:"extra-vars" form:"extra-vars" query:"extra-vars"`
Arguments []string `json:"arguments" xml:"arguments" form:"arguments" query:"arguments"`
Args []string
}
func (p *Playbook) formatArgs() {
// is it worth iterating through directly with reflection instead of using structs import?
// https://stackoverflow.com/questions/21246642/iterate-over-string-fields-in-struct
m := structs.Map(p)
// direct assignment has the wrong type?
// arguments := m["arguments"]
arguments, _ := m["arguments"].([]string)
delete(m, "arguments")
for k, v := range m {
// Ignore non-strings and empty strings
if val, ok := v.(string); ok && val != "" {
key := playbookKeyDict[k]
if key == "" {
p.Args = append(p.Args, val)
} else {
p.Args = append(p.Args, playbookKeyDict[k], val)
}
}
}
p.Args = append(p.Args, arguments...)
}
Type assertion is used to get a value wrapped around using interface.
m := structs.Map(p)
Map(v interface{}){}
Map function is actually taking interface as its argument in the case stated. It is wrapping the type which is []string and its underlying value which is slice. The type can be checked using Relection reflect.TypeOf().
func TypeOf(i interface{}) Type
According to Russ Cox blog on Interfaces
Interface values are represented as a two-word pair giving a pointer
to information about the type stored in the interface and a pointer to
the associated data.
As specified in Golang spec
For an expression x of interface type and a type T, the primary
expression
x.(T)
asserts that x is not nil and that the value stored in x is of type T.
The notation x.(T) is called a type assertion.
For the error part:-
Cannot use 'arguments' (type interface{}) as type []string
We first needs to get the underlying value of type []string from interface using type assertion.

interface{} to []string

I'm trying to parse some YAML file into go struct, but the file itself can not be treated as ordinary go structure: some of values may be either string or map[string][]string.
What I have tried is to do custom unmarshal func:
func (domain *Domain) UnmarshalYAML(unmarshal func(interface{}) error) error {
fmt.Println("Parsing domain")
var hostUrl interface{}
unmarshal(&hostUrl)
fmt.Println(reflect.TypeOf(hostUrl))
switch hostUrl.(type) {
case string:
domain.Host = hostUrl.(string)
case map[interface {}]interface {}:
fmt.Println("got map")
v := reflect.ValueOf(hostUrl)
fmt.Println(v.MapKeys()[0])
for _, host := range v.MapKeys() {
domain.Host = host.Interface().(string)
fmt.Println(v.MapIndex(host))
//HERE I NEED TO DO SMTH LIKE THIS:
//domain.Urls = v.MapIndex(host).([]string)
}
default:
return errors.New("invalid config file, cant parse domains")
}
return nil
}
My domain structure looks like this:
type Domain struct {
Host string
Urls []string
}
But this code causes an error:
invalid type assertion: v.MapIndex(host).([]string) (non-interface type reflect.Value on left)
So my question may sound like "how to convert {}interface to []string?" or it may become more complex: "How to parse YAML file into go struct if some key can be either simple string or map[string][]string?"
UPDATE:
Responding to #mkopriva:
fmt.Println(v.MapIndex(host))
for url := range v.MapIndex(host).Interface().([] interface{}) {
fmt.Println(url)
}
Didnt help me, as now it just prints some integers (0), but there should be a string. Converting it to an array of strings throws another error:
panic: interface conversion: interface {} is []interface {}, not []string
Thanks to #mkopriva and the snippet from the sandbox. The reason of integer appearing during iterating over v.MapIndex(host).Interface().([] interface{}) is that range returns two values: index and corresponding to that index value. I was only catching the first one. It is why I wasn't able to cast it to string.
Working loop:
for _, url := range v.MapIndex(host).Interface().([] interface{}) {
fmt.Println(url.(string))
domain.Urls = append(domain.Urls,url.(string) )
}

Retrieving values from nested map in golang

I'm trying to retrieving a value from a map within a map. I have followed online tutorials but not getting the right answer. This is my program:
type OptionMap map[string]interface{}
func(options OptionMap) {
opt, _ := options["data2"].(OptionMap)
fmt.Println("opt", opt)
for key, value := range options {
fmt.Println("Key:", key, "Value:", value)
}
}
options has two keys data1 and data2 . Inside for loop the printf prints following
Key: data1 Value: false
Key: data2 Value: map[h:5]
When I run the code
opt, _ := options["data2"].(OptionMap)
I'm getting nil in opt. I'm not sure how to retrieve value of map[h:5].
You are getting nil value for inner map because you have not created inner map using type OptionMap.You must have created it using map[string]interface{} and trying to assert to OptionMap which is failing in getting nil value. See below example which is working with OptionMap type,too.Go through type assertion page at https://tour.golang.org/methods/15
package main
import "fmt"
type OptionMap map[string]interface{}
func main() {
opt := make(OptionMap)
ineeropt := make(OptionMap) // while creating Map specify OptionMap type
ineeropt["h"]=5
opt["data1"] = false
opt["data2"] = ineeropt
test(opt)
}
func test(options OptionMap) {
opt, _ := options["data2"].(OptionMap) //If inner map is created using OptionMap then opt won't be nil
fmt.Println("opt", opt)
fmt.Println("opt", options)
for key, value := range options {
fmt.Println("Key:", key, "Value:", value)
}
}

Resources