在 golang 的 flag 中自定义参数类型

1,875 阅读1分钟

Golang 的 flag 包能够帮助我们轻松实现一个命令行程序的参数解析,如:

package main

import (
   "flag"
   "fmt"
)

func main() {
   debug := flag.Bool("verbose", false, "Verbose log output.")
   name := flag.String("name", "", "your Name")
   
   flag.Parse()
   fmt.Println(*debug)
   fmt.Println(*name)
}

这个时候运行就可以看到我们命令行的参数:

image

Flag 是不区分短选项和长选项的(即不区分 flag、option、arguments 这些概念 unix.stackexchange.com/questions/2…

Flag 只支持简单的参数类型(bool、int、string),如果要使用复杂一些的类型,就需要自己去实现 Value 接口:

type Value interface {
   String() string
   Set(string) error
}

其中String方法格式化该类型的值,flag.Parse方法在执行时遇到自定义类型的选项会将选项值作为参数调用该类型变量的Set方法。

如最长被使用到的slice类型可以这么定义:

type arrayFlags []string

func (i *arrayFlags) String() string {
   return strings.Join(*i,", ")
}
func (i *arrayFlags) Set(value string) error {
   *i = append(*i, value)
   return nil
}

使用的时候使用 flag.Var

var exclusionGlobs arrayFlags

flag.Var(&exclusionGlobs, "exclude", "Glob of files that should not be pruned. Can be specified multiple times.")

在命令行中多次指定这个option就可以了,如

cli --exclude arg1 --exclude arg2

再比如使用 map 类型可以类似这样定义:

func (f mapFlag) String() string {
        return fmt.Sprintf("%v", map[string]string(f))
}

func (f mapFlag) Set(value string) error {
        split := strings.SplitN(value, "=", 2)
        f[split[0]] = split[1]
        return nil
}

func main() {
    var hostsFlag sliceFlag
    flag.Var(&hostsFlag, "env", "env list,for example: -env key1=value1 -env key2=value2")
}