Go Flag包详细使用指南 - Go语言编程资源

silverwq
2022-07-25 / 0 评论 / 227 阅读 / 正在检测是否收录...

概述

简单的实现了命令行参数的解析,复杂的命令解析方式可以使用以下两个库

  1. https://github.com/urfave/cli
  2. https://github.com/spf13/cobra

定义

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)

0

评论 (0)

取消