Go的标准库flag
由于其有不支持短选项,选项定义比较繁琐,默认只支持有限的数据类型。为了解决这些问题,出现了不少第三方解析命令行选项的库,go-flags
就是其中一个。
go-flags
提供了比标准库flag
更多的选项,它利用结构体的标签tag
和反射提供了一个方便、简洁的接口。除了基本的功能,还提供了其他丰富的特性:
支持短选项-v
和长选项-verbose
支持短选项合写,如-aux
同一选项可以设置多个值
支持所有基础类型和map类型,甚至函数
支持命名空间和选项组
等等…
使用go get
安装第三方库
$ go get github.com/jessevdk/go-flags
快速开始
type Option struct {
Names []string `short:"n" long:"name" description:"names of user"`
}
func main() {
var opt Option
flags.Parse(&opt)
fmt.Println(opt.Names)
}
运行程序
$ go run main.go --name test1 --name test2 --name test3
[test1 test2 test3]
使用go-flags
的一般步骤:
struct
结构体的tag中定义选项。short
定义短选项,long
定义长选项,description
设置帮助信息。flag
类似地,调用flags.Parse()
开始解析选项。go-flags
相比标准库flag
支持更丰富的数据类型:
string
,值为基础类型。Tips
切片类型选项,遇到相同的选项时,值会被追加到切片中。而非切片类型选项,如果遇到相同选项,后出现的值会覆盖先出现的值。
选项是函数类型:函数类型的参数有且仅有一个,作为函数的入参。
选项是map类型:键只能是string类型,值是基本的数据类型,格式为
key:value
示例
main.go:
type Option struct {
Names []string `short:"n" long:"name" description:"names of users"`
Age int `short:"a" long:"age" description:"age of user"`
Pointers []*string `short:"p" long:"pointer" description:"pointers of *string"`
Call func(int) `short:"c" long:"call" description:"call function"`
Values map[string]int `short:"v" long:"value" description:"values of user"`
}
func main() {
var opt Option
opt.Call = func(v int) {
// 预先定义好call属性的函数类型的实现,然后parse后会自动进行调用
fmt.Println("call function:", v)
}
if _, err := flags.Parse(&opt); err != nil {
panic("flags parse failed")
}
fmt.Println(opt.Names)
fmt.Println(opt.Age)
for _, p := range opt.Pointers {
fmt.Println(*p)
}
fmt.Println(opt.Values)
}
terminal:
$ go run main.go --name test1 -n test2 -n test3 -a 18 -a 19 -p pointer -c 18 -v k1:18
call function: 18
[test1 test2 test3]
19
pointer
map[k1:18]
required
为true时,对应的选项必须设置值,否则会抛出ErrRequired
错误
default
用于设置选项的默认值,即选项如果没有设置值的时候,会使用此默认值
main.go
type Config struct {
Name string `short:"n" required_default:"true"`
Gender string `short:"g" default:"man"`
}
func main() {
var config Config
if _, err := flags.Parse(&config); err != nil {
log.Fatal("parse failed:", err)
}
fmt.Println(config.Name)
fmt.Println(config.Gender)
}
terminal
$ go run main.go -n test
test
man
main.go
type Option struct {
Name string `long:"name"`
Info InfoOption `group:"info"`
Contact ContactOption `group:"contact"`
}
type InfoOption struct {
Gender bool `long:"gender"`
Age int `long:"age"`
}
type ContactOption struct {
Email string `long:"email"`
Phone string `long:"phone"`
}
func main() {
var opt Option
if _, err := flags.Parse(&opt); err != nil {
log.Fatalln("flags parse failed:", err)
}
fmt.Println(opt.Name)
fmt.Println(opt.Info)
fmt.Println(opt.Contact)
}
将分组的选项拆分到另外两个结构体当中,并且在父结构体中使用时,加上Tag:group:""
terminal
$ go run main.go --name test --gender --age 18 --email abc@example.com --phone 1111111
test
{true 18}
{abc@example.com 1111111}