go 反射注册 flag

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

标签: go

添加新评论