具有标志指针值的反射结构 field.Set

Reflection struct field.Set with a Flag pointer value

我解析了一堆标志,然后我试图将这些值分配给结构中的字段,但我正在努力将解析的标志值设置到结构中,因为我无法键入断言或施放它。

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

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是一个接口类型flag.Value抽象了各种标志值。正如您的代码所示,它不是 bool 类型,而是 non-exported *flag.boolValue 类型。你不应该关心它的动态类型。

您可以使用 Value.String() 方法将其值作为 string 获取,对于 bool 类型,这将是 "false""true",您可以使用简单的比较从中获得 bool 就像 f.Value.String() == "true".

但更好的方法是:所有源自 flag 包的 flag.Value 值也实现 flag.Getter,它也有一个 Get() 方法,将直接 return 一个 bool 值在 bool 标志的情况下(当然包装在 interface{} 中)。只需使用它:

field.Set(reflect.ValueOf(f.Value.(flag.Getter).Get()))

以上适用于任何类型的字段(假定标志的值类型可分配给字段的类型)。

仅适用于 bool 个字段,或者您也可以使用:

field.SetBool(f.Value.(flag.Getter).Get().(bool))