go基础库之使用flag包创建程序交互操作

golang 基础库之go获取命令行参数,介绍了如何使用flag包创建程序交互操作

使用flag包创建程序交互操作

Golang 版本

1.12.1

前言

通过flag定义程序交互接口的方法主导了基于GNU/LinuxBSDmacOS的系统。比如ls -l*NIX系统上列出当前目录中的文件就是一个典型的例子。 Go版本的flag包不支持flag的组合,例如ls -ll,所以每个flag必须分开。还有就是Go flag包也不区分长短选项。最后,-flag--flag是等价的。

实现

package main
import (
"flag"
"fmt"
"log"
"os"
"strings"
)

// 自定义类型需要实现flag.Value
// 接口才能在flag.Var函数中使用它
type ArrayValue []string

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

func (a *ArrayValue) Set(s string) error {
	*a = strings.Split(s, ",")
	return nil
}

func main() {

	// 使用返回指针的方法提取flag值
	retry := flag.Int("retry", -1, "定义最大重试次数")

	// 使用XXXVar方法读取flag值
	// 在这种情况下,必须在标志之前定义变量
	var logPrefix string
	flag.StringVar(&logPrefix, "prefix", "", "Logger 前缀")

	var arr ArrayValue
	flag.Var(&arr, "array", "输入数组迭代")

	// 执行flag.Parse函数,
	// 读取已定义变量的flag。
	// 没有这个调用,flag变量保持为空。
	flag.Parse()

	// 与flag功能无关,只是例子逻辑的一部分
	logger := log.New(os.Stdout, logPrefix, log.LstdFlags)

	retryCount := 0
	for retryCount < *retry {
		logger.Println("连接重试...")
		logger.Printf("发送的数组 %v\n", arr)
		retryCount++
	}
}

通过 go build -o util 编译为二进制文件

在命令行中执行 ./util -retry 2 -prefix=test -array=1,2,3

返回如下结果

$ ./util -retry 2 -prefix test -array=1,2,3
test2019/05/14 08:52:45 连接重试...
test2019/05/14 08:52:45 发送的数组 [1 2 3]
test2019/05/14 08:52:45 连接重试...
test2019/05/14 08:52:45 发送的数组 [1 2 3]

原理

对于在程序中获取flag值,flag包定义了两种类型的函数。

第一种类型是简单名称,比如Int。此函数将返回指向已解析flag值的整数变量的指针。

第二种是xxxVar这种类型的方法。它们提供相同的功能,但你需要提供指向变量的指针,以便于将解析的flag值存储在给定的变量中。

Go 库还支持自定义flag类型,函数是Var。自定义类型必须实现flag包中value的接口。上述代码中ArrayValue变量就是实现了flag包中valueStringSet接口。

上面代码最重要部分是parse()解析flag的函数。在定义所有flag之后并且在访问值之前,必须进行调用,否则将获取不到传入的值。

延伸

flag包中还包含flag处理的底层函数,以满足不同的需求,推荐阅读一下FlagSet的文档。