func (fs *Flags) Float64Opt(p *float64, name, shorts string, defValue float64, desc string) {
	fs.float64Opt(p, newFlagMeta(name, desc, defValue, splitShortcut(shorts)))
}
Float64Opt binding an float64 option
package gcli
import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"reflect"
	"strings"
	"unsafe"
	"github.com/gookit/color"
	"github.com/gookit/goutil"
	"github.com/gookit/goutil/arrutil"
	"github.com/gookit/goutil/strutil"
)
const (
	AlignLeft  = strutil.PosRight
	AlignRight = strutil.PosLeft
	defaultDesc = "No description"
	TagRuleNamed = 0
	TagRuleSimple = 1
)
var (
	FlagTagName = "flag"
	flagTagKeys = arrutil.Strings{"name", "shorts", "desc", "default", "required"}
)
type FlagsOption struct {
	WithoutType bool
	NameDescOL bool
	Alignment uint8
	TagName string
	TagRuleType uint8
}
type Flags struct {
	Desc string
	ExitFunc func(code int)
	opt *FlagsOption
	fSet *flag.FlagSet
	buf *bytes.Buffer
	out io.Writer
	names map[string]int
	metas map[string]*FlagMeta  
	shorts map[string]string
	name2shorts map[string][]string
	flagMaxLen int
	existShort bool
}
func newDefaultFlagOption() *FlagsOption {
	return &FlagsOption{
		Alignment: AlignRight,
		TagName:   FlagTagName,
	}
}
func NewFlags(nameWithDesc ...string) *Flags {
	fs := &Flags{
		out: os.Stdout,
		opt: newDefaultFlagOption(),
	}
	fs.ExitFunc = os.Exit
	fName := "gflag"
	if num := len(nameWithDesc); num > 0 {
		fName = nameWithDesc[0]
		if num > 1 {
			fs.Desc = nameWithDesc[1]
		}
	}
	fs.InitFlagSet(fName)
	return fs
}
var flagValueType = reflect.TypeOf(new(flag.Value)).Elem()
var errNotPtrValue = errors.New("must provide an ptr value")
var errNotAnStruct = errors.New("must provide an struct ptr")
var errTagRuleType = errors.New("invalid tag rule type on struct")
func (fs *Flags) FromStruct(ptr interface{}) error {
	v := reflect.ValueOf(ptr)
	if v.Kind() != reflect.Ptr {
		return errNotPtrValue
	}
	if !v.IsNil() {
		v = v.Elem()
	}
	t := v.Type()
	if t.Kind() != reflect.Struct {
		return errNotAnStruct
	}
	tagName := fs.opt.TagName
	if tagName == "" {
		tagName = FlagTagName
	}
	var mp map[string]string
	for i := 0; i < t.NumField(); i++ {
		sf := t.Field(i)
		name := sf.Name
		if name[0] >= 'a' && name[0] <= 'z' {
			continue
		}
		str := sf.Tag.Get(tagName)
		if str == "" {
			continue
		}
		fv := v.Field(i)
		ft := t.Field(i).Type
		if !fv.CanInterface() {
			continue
		}
		if ft.Kind() == reflect.Ptr {
			if fv.IsNil() {
				return fmt.Errorf("field: %s - nil pointer dereference", name)
			}
			ft = ft.Elem()
			fv = fv.Elem()
		}
		if fs.opt.TagRuleType == TagRuleNamed {
			mp = parseNamedRule(name, str)
		} else if fs.opt.TagRuleType == TagRuleSimple {
			mp = parseSimpleRule(name, str)
		} else {
			return errTagRuleType
		}
		defVal := mp["default"]
		shorts := splitShortcut(mp["shorts"])
		optName, has := mp["name"]
		if !has {  
			optName = strutil.SnakeCase(name, "-")
		}
		meta := newFlagMeta(optName, mp["desc"], defVal, shorts)
		if must, has := mp["required"]; has {
			meta.Required = strutil.MustBool(must)
		}
		if ft.Implements(flagValueType) {
			fs.Var(fv.Interface().(flag.Value), meta)
			continue
		}
		ptr := unsafe.Pointer(fv.UnsafeAddr())
		switch ft.Kind() {
		case reflect.Bool:
			fs.BoolVar((*bool)(ptr), meta)
		case reflect.Int:
			fs.IntVar((*int)(ptr), meta)
		case reflect.Int64:
			fs.Int64Var((*int64)(ptr), meta)
		case reflect.Uint:
			fs.UintVar((*uint)(ptr), meta)
		case reflect.Uint64:
			fs.Uint64Var((*uint64)(ptr), meta)
		case reflect.Float64:
			fs.Float64Var((*float64)(ptr), meta)
		case reflect.String:
			fs.StrVar((*string)(ptr), meta)
		default:
			return fmt.Errorf("field: %s - invalid type for binding flag", name)
		}
	}
	return nil
}
func (fs *Flags) SetOptions(opt *FlagsOption) {
	fs.opt = opt
}
func (fs *Flags) UseSimpleRule() *Flags {
	fs.opt.TagRuleType = TagRuleSimple
	return fs
}
func (fs *Flags) WithOptions(fns func(opt *FlagsOption)) *Flags {
	fns(fs.opt)
	return fs
}
func (fs *Flags) InitFlagSet(name string) {
	if fs.fSet != nil {
		return
	}
	fs.fSet = flag.NewFlagSet(name, flag.ContinueOnError)
	fs.fSet.SetOutput(ioutil.Discard)
	fs.fSet.Usage = func() {}
}
func (fs *Flags) Run(args []string) {
	if args == nil {
		args = os.Args
	}
	binFile, waitArgs := args[0], args[1:]
	fs.SetHelpRender(func() {
		if fs.Desc != "" {
			color.Infoln(fs.Desc)
		}
		color.Comment.Println("Usage:")
		color.Cyan.Println(" ", binFile, "[--OPTIONS...]\n")
		color.Comment.Println("Options:")
		fs.PrintHelpPanel()
	})
	if err := fs.Parse(waitArgs); err != nil {
		if err == flag.ErrHelp {
			fs.ExitFunc(0)
		} else {
			color.Errorf("flag parse error - %s", err.Error())
			fs.ExitFunc(2)
		}
	}
}
func (fs *Flags) Parse(args []string) (err error) {
	err = fs.fSet.Parse(args)
	if err != nil {
		return
	}
	for name, meta := range fs.metas {
		fItem := fs.fSet.Lookup(name)
		err = meta.Validate(fItem.Value.String())
		if err != nil {
			return err
		}
	}
	return
}
func (fs *Flags) RawArg(i int) string {
	return fs.fSet.Arg(i)
}
func (fs *Flags) RawArgs() []string {
	return fs.fSet.Args()
}
func (fs *Flags) FSetArgs() []string {
	return fs.fSet.Args()
}
func (fs *Flags) Bool(name, shorts string, defValue bool, desc string) *bool {
	meta := newFlagMeta(name, desc, defValue, splitShortcut(shorts))
	name = fs.checkFlagInfo(meta)
	p := fs.fSet.Bool(name, defValue, meta.Desc)
	for _, s := range meta.Shorts {
		fs.fSet.BoolVar(p, s, defValue, "")  
	}
	return p
}
func (fs *Flags) BoolVar(p *bool, meta *FlagMeta) {
	fs.boolOpt(p, meta)
}
func (fs *Flags) BoolOpt(p *bool, name, shorts string, defValue bool, desc string) {
	fs.boolOpt(p, newFlagMeta(name, desc, defValue, splitShortcut(shorts)))
}
func (fs *Flags) boolOpt(p *bool, meta *FlagMeta) {
	defVal := meta.DValue().Bool()
	fmtName := fs.checkFlagInfo(meta)
	fs.fSet.BoolVar(p, fmtName, defVal, meta.Desc)
	for _, s := range meta.Shorts {
		fs.fSet.BoolVar(p, s, defVal, "")  
	}
}
func (fs *Flags) Float64Var(p *float64, meta *FlagMeta) {
	fs.float64Opt(p, meta)
}