1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| package main
import ( "flag" "fmt" "reflect" "strconv" "strings" "time" "unsafe" )
func registerOptions(prefix string, rt reflect.Type, base uintptr) { nfield := rt.NumField() for i := 0; i < nfield; i++ { f := rt.Field(i) name := f.Tag.Get("name") if name == "" { name = strings.ToLower(f.Name) } if prefix != "" { name = prefix + "-" + name } def := f.Tag.Get("def") usage := f.Tag.Get("usage") if usage == "" { usage = strings.ToLower(f.Type.Name()) } switch f.Type.Kind() { case reflect.String: flag.StringVar((*string)(unsafe.Pointer(base+f.Offset)), name, def, usage) case reflect.Bool: bdef, _ := strconv.ParseBool(def) flag.BoolVar((*bool)(unsafe.Pointer(base+f.Offset)), name, bdef, usage) case reflect.Int: idef, _ := strconv.Atoi(def) flag.IntVar((*int)(unsafe.Pointer(base+f.Offset)), name, idef, usage) case reflect.Int64: if f.Type.AssignableTo(reflect.TypeOf(time.Duration(0))) { ddef, _ := time.ParseDuration(def) flag.DurationVar((*time.Duration)(unsafe.Pointer(base+f.Offset)), name, ddef, usage) } else { i64def, _ := strconv.ParseInt(def, 10, 64) flag.Int64Var((*int64)(unsafe.Pointer(base+f.Offset)), name, i64def, usage) } case reflect.Ptr: registerOptions(name, f.Type.Elem(), base+f.Offset) case reflect.Struct: registerOptions(name, f.Type, base+f.Offset) default: panic("unsupport option type: " + f.Type.String()) } } }
var options struct { Hello string World int Redis struct { Addr string Auth string } }
func main() { registerOptions("", reflect.TypeOf(options), uintptr(unsafe.Pointer(&options))) flag.Parse() fmt.Println(options) }
|