I have a bunch of flags parsed, and I'm then trying to assign those values to fields in a struct, but I'm struggling to get a parsed flag value set into the struct because I can't type assert it or cast it.
Here is a snippet of the code I have. It's not important to worry too much about the IterFields
function, basically the third argument is called for each field in the struct...
Note: there are comments in the code below which highlight the error(s).
flag.Parse()
IterFields(st, v, func(field reflect.Value, sf reflect.StructField) {
flag.VisitAll(func(f *flag.Flag) {
if f.Name == strings.ToLower(sf.Name) || f.Name == sf.Tag.Get("short") {
fmt.Printf("%+v, %T\n", f.Value, f.Value)
// PRINTS: true, *flag.boolValue
if v, ok := f.Value.(bool); ok {
fmt.Println("ok")
} else {
fmt.Println("not ok")
}
// ERROR: impossible type assertion: bool does not implement flag.Value (missing Set method)
field.Set(reflect.ValueOf(f.Value))
// PANIC: value of type *flag.boolValue is not assignable to type bool
}
})
})
f.Value
is an interface type flag.Value
abstracting all kinds of flag values. As your code indicates, it's not of type bool
but some non-exported *flag.boolValue
. You shouldn't be concerned about its dynamic type.
You may use the Value.String()
method to get its value as a string
, which will be either "false"
or "true"
for bool types, you may use simple comparison to obtain a bool
from it like f.Value.String() == "true"
.
But a better approach would be: all flag.Value
values originating from the flag
package also implement flag.Getter
which also has a Get()
method that will directly return a bool
value in case of a bool flag (wrapped in interface{}
of course). Just use that:
field.Set(reflect.ValueOf(f.Value.(flag.Getter).Get()))
The above works for fields of any type (given that the flag's value type is assignable to the field's type).
For bool
fields only, alternatively you may also use:
field.SetBool(f.Value.(flag.Getter).Get().(bool))