概述
简单的实现了命令行参数的解析,复杂的命令解析方式可以使用以下两个库
定义
flag.Xxx() 方式,Xxx 可以是 Int、String 等类型,返回一个相应类型的指针
func main() {
var name = flag.String("name", "", "名字")
var age = flag.Int("age", 0, "年龄")
flag.Parse()
// 名字是: zhangSan 年龄是: 30
fmt.Println("名字是:", *name, "年龄是:", *age)
}
flag.XxxVar()方式,绑定到一个变量上,也是传入变量的指针
func main() {
var name string
var age int
flag.StringVar(&name,"name", "", "名字")
flag.IntVar(&age,"age", 0, "年龄")
flag.Parse()
// go run main.go -name 张三 -age 30
// 名字是: 张三 年龄是: 30
fmt.Println("名字是:", name, "年龄是:", age)
}
flag.Var()方式,自定义类型,要实现 flag.Value 接口即可
// 自定义类型
type hobbyValues []string
// Set String 实现了flag.value 接口
func (s *hobbyValues) Set(val string) error {
*s = hobbyValues(strings.Split(val, ","))
return nil
}
func (s *hobbyValues) String() string {
return strings.Join([]string(*s), ",")
}
// Get 实现了flag.Getter接口,这个接口可以不实现
func (s *hobbyValues) Get() interface{} {
return []string(*s)
}
func main() {
var hobby hobbyValues
flag.Var(&hobby, "hobby", "兴趣爱好,多个的话用,分隔")
flag.Parse()
// go run main.go -hobby 游泳,看书
// 兴趣爱好是: [游泳 看书]
fmt.Println("兴趣爱好是:", hobby)
}
解析
在所有的 flag 定义完成之后,可以通过调用 flag.Parse()
进行解析,语法有三种形式
// 只支持 bool 类型,省略的话就是默认值
-flag // true
-flag=false // 可以使用的值有:1, 0, t, f, true, false, TRUE, FALSE, True, False
// bool 和非 bool 类型都支持这个写法
-flag=x
// 只支持非 bool 类型
-flag x
类型
ErrorHandling 类型,该类型定义了在参数解析出错时错误处理方式
type ErrorHandling int
const (
ContinueOnError ErrorHandling = iota // 错误的话是打印详情
ExitOnError // 错误的话是退出程序
PanicOnError // 错误的话是异常
)
Flag 类型, 代表一个 flag 的状态
// flag.Parse() 之后,会存各个命令参数的值信息
type Flag struct {
Name string // name as it appears on command line
Usage string // help message
Value Value // value as set
DefValue string // default value (as text); for usage message
}
FlagSet 类,flag 集合的信息,flag 集合的信息
// A FlagSet represents a set of defined flags.
type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags.
// The field is a function (not a method) that may be changed to point to
// a custom error handler.
Usage func()
name string // FlagSet 的名字。CommandLine 给的是 os.Args[0]
parsed bool // 是否执行过 Parse()
actual map[string]*Flag // 存放实际传递了的参数(即命令行参数)
formal map[string]*Flag // 存放所有已定义命令行参数
args []string // arguments after flags // 开始存放所有参数,最后保留 非 flag(non-flag)参数
exitOnError bool // does the program exit if there's an error?
errorHandling ErrorHandling // 当解析出错时,处理错误的方式
output io.Writer // nil means stderr; use out() accessor
}
Value 接口,所有参数类型需要实现 Value 接口,flag 包中,为 int、float、bool 等实现了该接口,借助该接口,我们可以自定义 flag
// Value is the interface to the dynamic value stored in a flag.
// (The default value is represented as a string.)
type Value interface {
String() string
Set(string) error
}
函数
go 标准库中,经常这么做,一个包中有个类型,为了方便使用会示例一个该类型的实例
// Flag 包里实例化FlagSet的实例
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
封装
func Parse() bool {
return CommandLine.Parse()
}
// FlagSet类的方法
func (f *FlagSet) Parsed() bool {
return f.parsed
}
这样就方便的调用到 flagSet 类的 parse 方法了
// 实际上是调用flag.CommandLine.Parse() 方法
flag.Parse()
主要方法
NewFlagSet()
用于实例化 FlagSet
// 默认的 FlagSet 实例在解析出错时会退出程序
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
Parse()
解析参数
func Parse() {
// 方法参数 arguments 不包括命令名,即应该是 os.Args[1:]
CommandLine.Parse(os.Args[1:])
}
调用真正解析参数的非导出方法: parseOne
func (f *FlagSet) Parse(arguments []string) error {
seen, err := f.parseOne()
}
Parse 出错时默认是会退出程序
func (f *FlagSet) Parse(arguments []string) error {
switch f.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
if err == ErrHelp {
os.Exit(0)
}
os.Exit(2)
case PanicOnError:
panic(err)
}
}
解析什么时候停止?当 parseOne 返回 false, nil
时,Parse 解析终止,当遇到单独的一个 "-" 或不是 "-" 开始时,会停止解析
// 单独的一个-
./nginx - -c
// build,不是-开始
./nginx build -c
单独--开头的
./nginx -- 或者 ./nginx -c default.confg -- test
./nginx -c -- //这种不算,这种--相当于-c的值
Arg(i int) 和 Args()
Arg(i int) 和 Args() 这两个方法就是获取 non-flag
参数的
NArg()
NArg() 获得 non-flag
的个数
NFlag()
NFlag() 获得 FlagSet 中 actual 长度(即被设置了的参数个数)
Visit/VisitAll
这两个函数分别用于访问 FlatSet 的 actual 和 formal 中的 Flag,而具体的访问方式由调用者决定
PrintDefaults()
打印所有已定义参数的默认值(调用 VisitAll 实现),默认输出到标准错误,除非指定了 FlagSet 的 output(通过 SetOutput() 设置)
Set(name, value string)
设置某个 flag 的值(通过 name 查找到对应的 Flag)