缘起
我一直在想,有什么方式可以让人比较轻易地保持每日学习,持续输出的状态。写博客是一种方式,但不是每天都有想写的,值得写的东西。 有时候一个技术比较复杂,写博客的时候经常会写着写着发现自己的理解有偏差,或者细节还没有完全掌握,要去查资料,了解了之后又继续写,如此反复。 这样会导致一篇博客的耗时过长。
我在每天浏览思否、掘金和Github的过程中,发现一些比较好的想法,有JS 每日一题,NodeJS 每日一库,每天一道面试题等等等等。 https://github.com/parro-it/awesome-micro-npm-packages这个仓库收集 NodeJS 小型库,一天看一个不是梦!这也是我这个系列的灵感。 我计划每天学习一个 Go 语言的库,输出一篇介绍型的博文。每天一库当然是理想状态,我心中的预期是一周 3-5 个。
flag
简介
flagls -al-al
命令行选项在实际开发中很常用,特别是在写工具的时候。
redis-server ./redis.confredis.confpython -m SimpleHTTPServer 8080
快速使用
flag
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 (
"fmt"
"flag"
)
var (
intflag int
boolflag bool
stringflag string
)
func init() {
flag.IntVar(&intflag, "intflag", 0, "int flag value")
flag.BoolVar(&boolflag, "boolflag", false, "bool flag value")
flag.StringVar(&stringflag, "stringflag", "default", "string flag value")
}
func main() {
flag.Parse()
fmt.Println("int flag:", intflag)
fmt.Println("bool flag:", boolflag)
fmt.Println("string flag:", stringflag)
}
可以先编译程序,然后运行(我使用的是 Win10 + Git Bash):
1
2
$ go build -o main.exe main.go
$ ./main.exe -intflag 12 -boolflag 1 -stringflag test
输出:
1
2
3
int flag: 12
bool flag: true
string flag: test
如果不设置某个选项,相应变量会取默认值:
1
$ ./main.exe -intflag 12 -boolflag 1
输出:
1
2
3
int flag: 12
bool flag: true
string flag: default
stringflagdefault
go run
1
$ go run main.go -intflag 12 -boolflag 1
-h
1
2
3
4
5
6
7
8
$ ./main.exe -h
Usage of D:\code\golang\src\github.com\darjun\cmd\flag\main.exe:
-boolflag
bool flag value
-intflag int
int flag value
-stringflag string
string flag value (default "default")
flag
intflag/boolflag/stringflaginitflag.TypeVarTypeInt/Uint/Float64/Booltime.Durationmainflag.Parseos.Args[1:]os.Args[0]
注意点:
flag.Parseflag.Parseinitinitmainflag.Parse
选项格式
flag
1
2
3
-flag
-flag=x
-flag x
------flag
true
1
cmd -x *
*-xfalse-xtruefalse-flag=false
-----
1
$ ./main.exe noflag -intflag 12
将会输出:
1
2
3
int flag: 0
bool flag: false
string flag: default
noflag-intflag
运行下面的程序:
1
$ ./main.exe -intflag 12 -- -boolflag=true
将会输出:
1
2
3
int flag: 12
bool flag: false
string flag: default
intflag----boolflag=trueboolflagfalse
flagflag.Argsflag.NArgflag.Arg(i)iflag.NFlag
稍稍修改一下上面的程序:
1
2
3
4
5
6
7
8
9
10
11
func main() {
flag.Parse()
fmt.Println(flag.Args())
fmt.Println("Non-Flag Argument Count:", flag.NArg())
for i := 0; i < flag.NArg(); i++ {
fmt.Printf("Argument %d: %s\n", i, flag.Arg(i))
}
fmt.Println("Flag Count:", flag.NFlag())
}
编译运行该程序:
1
2
$ go build -o main.exe main.go
$ ./main.exe -intflag 12 -- -stringflag test
输出:
1
2
3
4
[-stringflag test]
Non-Flag Argument Count: 2
Argument 0: -stringflag
Argument 1: test
---stringflag testflagArgs/NArg/Arg
flagstrconv.ParseIntintParseInt
布尔类型的选项值可以为:
truefalse
另一种定义选项的方式
flag.TypeVarflag.TypeTypeInt/Uint/Bool/Float64/String/Duration
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 (
"fmt"
"flag"
)
var (
intflag *int
boolflag *bool
stringflag *string
)
func init() {
intflag = flag.Int("intflag", 0, "int flag value")
boolflag = flag.Bool("boolflag", false, "bool flag value")
stringflag = flag.String("stringflag", "default", "string flag value")
}
func main() {
flag.Parse()
fmt.Println("int flag:", *intflag)
fmt.Println("bool flag:", *boolflag)
fmt.Println("string flag:", *stringflag)
}
编译并运行程序:
1
2
$ go build -o main.exe main.go
$ ./main.exe -intflag 12
将输出:
1
2
3
int flag: 12
bool flag: false
string flag: default
除了使用时需要解引用,其它与前一种方式基本相同。
高级用法
定义短选项
flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import (
"fmt"
"flag"
)
var logLevel string
func init() {
const (
defaultLogLevel = "DEBUG"
usage = "set log level value"
)
flag.StringVar(&logLevel, "log_type", defaultLogLevel, usage)
flag.StringVar(&logLevel, "l", defaultLogLevel, usage + "(shorthand)")
}
func main() {
flag.Parse()
fmt.Println("log level:", logLevel)
}
编译、运行程序:
1
2
3
$ go build -o main.exe main.go
$ ./main.exe -log_type WARNING
$ ./main.exe -l WARNING
使用长、短选项均输出:
1
log level: WARNING
不传入该选项,输出默认值:
1
2
$ ./main.exe
log level: DEBUG
解析时间间隔
flagtime.Durationflagtime.ParseDuration
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main
import (
"flag"
"fmt"
"time"
)
var (
period time.Duration
)
func init() {
flag.DurationVar(&period, "period", 1*time.Second, "sleep period")
}
func main() {
flag.Parse()
fmt.Printf("Sleeping for %v...", period)
time.Sleep(period)
fmt.Println()
}
period
1
2
3
4
5
6
$ go build -o main.exe main.go
$ ./main.exe
Sleeping for 1s...
$ ./main.exe -period 1m30s
Sleeping for 1m30s...
自定义选项
flag
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
34
35
36
37
38
39
40
41
42
43
package main
import (
"errors"
"flag"
"fmt"
"strings"
"time"
)
type interval []time.Duration
func (i *interval) String() string {
return fmt.Sprint(*i)
}
func (i *interval) Set(value string) error {
if len(*i) > 0 {
return errors.New("interval flag already set")
}
for _, dt := range strings.Split(value, ",") {
duration, err := time.ParseDuration(dt)
if err != nil {
return err
}
*i = append(*i, duration)
}
return nil
}
var (
intervalFlag interval
)
func init() {
flag.Var(&intervalFlag, "deltaT", "comma-seperated list of intervals to use between events")
}
func main() {
flag.Parse()
fmt.Println(intervalFlag)
}
interval
flag.Value
1
2
3
4
5
// src/flag/flag.go
type Value interface {
String() string
Set(string) error
}
Stringflag.ParseSet,
flag.Var
编译、执行程序:
1
2
3
4
5
$ go build -o main.exe main.go
$ ./main.exe -deltaT 30s
[30s]
$ ./main.exe -deltaT 30s,1m,1m30s
[30s 1m0s 1m30s]
SeterrorParse
1
2
3
4
5
$ ./main.exe -deltaT 30x
invalid value "30x" for flag -deltaT: time: unknown unit x in duration 30x
Usage of D:\code\golang\src\github.com\darjun\go-daily-lib\flag\self-defined\main.exe:
-deltaT value
comma-seperated list of intervals to use between events
解析程序中的字符串
flag.FlagSet
flagFlagSetflagFlagSetCommandLineflagCommandLine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/flag/flag.go
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
func Parse() {
CommandLine.Parse(os.Args[1:])
}
func IntVar(p *int, name string, value int, usage string) {
CommandLine.Var(newIntValue(value, p), name, usage)
}
func Int(name string, value int, usage string) *int {
return CommandLine.Int(name, value, usage)
}
func NFlag() int { return len(CommandLine.actual) }
func Arg(i int) string {
return CommandLine.Arg(i)
}
func NArg() int { return len(CommandLine.args) }
FlagSet
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
package main
import (
"flag"
"fmt"
)
func main() {
args := []string{"-intflag", "12", "-stringflag", "test"}
var intflag int
var boolflag bool
var stringflag string
fs := flag.NewFlagSet("MyFlagSet", flag.ContinueOnError)
fs.IntVar(&intflag, "intflag", 0, "int flag value")
fs.BoolVar(&boolflag, "boolflag", false, "bool flag value")
fs.StringVar(&stringflag, "stringflag", "default", "string flag value")
fs.Parse(args)
fmt.Println("int flag:", intflag)
fmt.Println("bool flag:", boolflag)
fmt.Println("string flag:", stringflag)
}
NewFlagSet
ContinueOnErrorCommandLineExitOnErroros.Exit(2)PanicOnError
flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// src/flag/flag.go
func (f *FlagSet) Parse(arguments []string) error {
f.parsed = true
f.args = arguments
for {
seen, err := f.parseOne()
if seen {
continue
}
if err == nil {
break
}
switch f.errorHandling {
case ContinueOnError:
return err
case ExitOnError:
os.Exit(2)
case PanicOnError:
panic(err)
}
}
return nil
}
flagFlagSetParseflag.ParseCommandLine.Parse(os.Args[1:])