package command import ( "errors" "flag" "reflect" "strconv" ) type FVSet struct { Name string Value *any flags flag.FlagSet } func (f *FVSet) Parse(args []string) error { return f.flags.Parse(args) } func isPtr(v interface{}) bool { return reflect.TypeOf(v).Kind() == reflect.Ptr } // NewFVSet 创建一个新的FVSet实例,用于处理命令行标志。 // 参数v是一个指向结构体的指针,该结构体的字段将被用作命令行标志。 // 返回值是一个指向FVSet的指针和一个错误对象,如果操作成功,错误对象为nil。 // 如果v不是指向结构体的指针,函数将返回错误。 func NewFVSet(v interface{}) (*FVSet, error) { // 判断v是不是指针 vv := reflect.ValueOf(v) if !isPtr(v) { return nil, errors.New("v must be a pointer") } // 判断指针指向的值是不是结构体 vvv := vv.Elem() if vvv.Kind() != reflect.Struct { return nil, errors.New("v must be a pointer to a struct") } flags := flag.NewFlagSet(vvv.Type().Name(), flag.ContinueOnError) name := vvv.Type().Name() // 遍历结构体字段 for i := 0; i < vvv.NumField(); i++ { //skip private field stField := vvv.Type().Field(i) if stField.PkgPath != "" { continue } // 获取字段名 field := vvv.Field(i) nameTag := stField.Tag.Get("flag_name") flaName := nameTag if flaName == "" { flaName = stField.Name } defVal := stField.Tag.Get("flag_default") usageStr := stField.Tag.Get("flag_usage") if usageStr == "" { usageStr = "Set " + flaName + "(default " + defVal + ")" } if field.CanSet() { switch expression := field.Interface().(type) { case string: flags.StringVar(&expression, flaName, defVal, usageStr) break case int: v, _ := strconv.Atoi(defVal) flags.IntVar(&expression, flaName, v, usageStr) break case bool: flags.BoolVar(&expression, flaName, false, usageStr) break default: return nil, errors.New("unsupported type") } } } return &FVSet{ Name: name, Value: &v, flags: *flags, }, nil } // Parse is used to parse command line arguments based on one or more flag sets. // args represents the list of command line arguments. // flagSet is a variable-length parameter that contains the flag sets to be parsed. // If no flag set is provided, it throws a panic exception. // If only one flag set is provided, it directly parses the arguments with that flag set. // If multiple flag sets are provided, it attempts to match and parse based on the first argument in args. // If no matching flag set is found, it returns an error. func Parse(args []string, flagSet ...*FVSet) error { // Check if the flag set is missing, if so, throw a panic exception. if len(flagSet) == 0 { panic("flag set missing") } // If only one flag set is provided, directly parse the arguments with that flag set. if len(flagSet) == 1 { return flagSet[0].Parse(args) } // Iterate through the flag sets to find a match for parsing. for _, f := range flagSet { // If a matching flag set is found, parse the remaining arguments with that flag set. if f.Name == args[0] { return f.Parse(args[1:]) } } // If no matching flag set is found, return an error. return errors.New("flag set not found") }