首页 > 解决方案 > 反射结构字段。使用标志指针值设置

问题描述

我解析了一堆标志,然后尝试将这些值分配给结构中的字段,但是我很难将解析的标志值设置到结构中,因为我无法键入断言或强制转换它.

这是我拥有的代码片段。过分担心IterFields函数并不重要,基本上结构中的每个字段都会调用第三个参数...

注意:下面的代码中有注释突出显示错误。

    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
            }
        })
    })

标签: pointersgocommand-line-interfacereflect

解决方案


f.Valueflag.Value是一种抽象各种标志值的接口类型。正如您的代码所示,它不是类型bool,而是一些 non-exported *flag.boolValue。你不应该关心它的动态类型。

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))

推荐阅读