Golang标准库学习 - flag
hanpy

flag 包实现了命令行参数的解析。

命令行选项格式

flag 库支持三种命令行选项格式。

1
2
3
-flag
-flag=x
-flag x

---都可以使用,它们的作用是一样的。
第一种形式只支持布尔类型的选项,出现即为true,不出现为默认值。 第三种形式不支持布尔类型的选项。因为这种形式的布尔选项在类 Unix 系统中可能会出现意想不到的行为。

接收参数

flag.Type 的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"flag"
"fmt"
)

var (
stringflag *string
intflag *int
boolflag *bool
)

func init() {
stringflag = flag.String("stringflag", "default", "提示: stringflag")
intflag = flag.Int("intflag", 10, "提示: intflag")
boolflag = flag.Bool("boolflag", false, "提示: boolflag")
}

func main() {
flag.Parse()

fmt.Println("int flag:", *intflag)
fmt.Println("bool flag:", *boolflag)
fmt.Println("string flag:", *stringflag)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 编译
➜ go build -o main -v main.go

# 无参数运行
➜ ./main
int flag: 10
bool flag: false
string flag: default

# 有参数运行
➜ ./main -stringflag=han -intflag=10 -boolflag
int flag: 10
bool flag: true
string flag: han

# 帮助命令
➜ ./main -h
Usage of ./main:
-boolflag
提示: boolflag
-intflag int
提示: intflag (default 10)
-stringflag string
提示: stringflag (default "default")

flag.TypeVar方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"flag"
"fmt"
)

var (
stringflag string
intflag int
boolflag bool
)

func init() {
flag.StringVar(&stringflag, "stringflag", "default", "提示: stringflag")
flag.IntVar(&intflag, "intflag", 10, "提示: intflag")
flag.BoolVar(&boolflag, "boolflag", false, "提示: boolflag")
}

func main() {
flag.Parse()

fmt.Println("int flag:", intflag)
fmt.Println("bool flag:", boolflag)
fmt.Println("string flag:", stringflag)
}

输出和 flag.Type 的方式是一样的。

flag.Var 方式

flag.Var 这种方式需要实现 flag.Value 接口

1
2
3
4
type Value interface {
String() string
Set(string) error
}

简单使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"flag"
"fmt"
"strings"
)

type List []string

func (l *List) String() string {
return fmt.Sprintf("%v", *l)
}

func (l *List) Set(s string) error {
// 分割字符串
split := strings.Split(s, ",")
*l = split
return nil
}

var l List

func init() {
flag.Var(&l, "list", "长标记-列表,用英文逗号分割")
flag.Var(&l, "l", "短标记-列表,用英文逗号分割")
}

func main() {
// 解析参数
flag.Parse()
fmt.Printf("listi s %v \n", l)
}

执行

1
2
3
4
5
6
7
8
9
10
11
12
➜ ./main -list=one,two,three
listi s [one two three]

➜ ./main -l=name,age,addr
listi s [name age addr]

➜ ./main- h
Usage of ./main:
-l value
短标记-列表,用英文逗号分割
-list value
长标记-列表,用英文逗号分割

解析程序中的字符串

有时候选项并不是通过命令行传递的。例如,从配置表中读取或程序生成的。这时候可以使用flag.FlagSet结构的相关方法来解析这些选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"flag"
"fmt"
)

func main() {
// 创建FlagSet类型变量
myFlagSet := flag.NewFlagSet("myFlag", flag.ExitOnError)

// 从切片中解析
// args := []string{"-intflag", "12", "-stringflag", "test"}
args := []string{"-intflag", "12", "-stringflag", "test"}
intflag := myFlagSet.Int("intflag", 10, "提示: intflag")
stringflag := myFlagSet.String("stringflag", "default", "提示: stringflag")
// 解析
myFlagSet.Parse(args)

// 打印
fmt.Printf("stringflag的值是 %v \n", *stringflag)
fmt.Printf("intflag的值是 %v \n", *intflag)
}
1
2
3
➜ ./main
stringflag的值是 test
intflag的值是 12

几个常用的数据结构

错误相关

1
2
3
4
5
6
7
type ErrorHandling int

const (
ContinueOnError ErrorHandling = iota // 发生错误后继续解析,返回错误
ExitOnError // 出错时调用os.Exit(2)退出程序
PanicOnError // 出错时产生 panic
)

Flag类型代表一条flag的状态。

1
2
3
4
5
6
type Flag struct {
Name string // flag在命令行中的名字
Usage string // 帮助信息
Value Value // 要设置的值
DefValue string // 默认值(文本格式),用于使用信息
}

FlagSet代表一个已注册的flag的集合。FlagSet零值没有名字,采用ContinueOnError错误处理策略。

1
2
3
4
5
6
7
8
9
10
type FlagSet struct {
Usage func() // 解析标志时发生错误时调用的函数
name string // FlagSet 的名字。CommandLine 给的是 os.Args[0]
parsed bool // 是否执行过 Parse()
actual map[string]*Flag // 存放实际传递了的参数(即命令行参数)
formal map[string]*Flag // 存放所有已定义命令行参数
args []string // 开始存放所有参数,最后保留 非 flag(non-flag)参数
errorHandling ErrorHandling // 当解析出错时,处理错误的方式
output io.Writer // nil means stderr; use Output() accessor
}