go 反射注册 flag

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