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.