flag
包定义了一系列函数,可用于定义命令行参数,支持的参数类型如下:
- string:flag.StringVar 函数
- bool:flag.BoolVar 函数
- time.Duration: flag.DurationVar 函数
- int: flag.IntVar 函数
- uint: flag.UintVar 函数
- float64: flag.Float64Var 函数
- int64: flag.Int64Var 函数
- uint64: flag.Uint64Var 函数
各函数声明见下图:
直接调用上述函数的话,会给默认的 CommandLine
定义一个命令行选项,内部则是调用了 FlagSet.Var
函数,如下:
// StringVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a string variable in which to store the value of the flag.
func StringVar(p *string, name string, value string, usage string) {
CommandLine.Var(newStringValue(value, p), name, usage)
}
// Var defines a flag with the specified name and usage string. The type and
// value of the flag are represented by the first argument, of type Value, which
// typically holds a user-defined implementation of Value. For instance, the
// caller could create a flag that turns a comma-separated string into a slice
// of strings by giving the slice the methods of Value; in particular, Set would
// decompose the comma-separated string into the slice.
func (f *FlagSet) Var(value Value, name string, usage string) {
// ...
}
FlagSet.Var
函数的第一个参数类型为 Value
,所以自定义选项类型需要从 Value
接口入手。
代码
Value
接口的声明如下(★ ★ ★ ★ ★):
type Value interface {
String() string
Set(string) error
}
自定义的选项类型要实现 Value
接口,完整代码如下:
// user_defined_flag_type.go
package main
import (
"errors"
"flag"
"fmt"
"strconv"
"strings"
)
// Gender 性别
type Gender int
const (
// genderMale 男性
genderMale Gender = iota
// genderFemale 女性
genderFemale
)
var (
// ErrUserParse 无法解析用户信息
ErrUserParse = errors.New("parse user error")
)
// User 自定义选项结构
// 支持以命令行选项的方式实例化,使用 : 作为分隔,选项值形如:`xiaoming:18:0`
type User struct {
Name string
age int
gender Gender
}
func (u *User) String() string {
return "user"
}
// Set 解析传递来的字符串,实例化 User 结构
func (u *User) Set(s string) error {
tokens := strings.Split(s, ":")
if len(tokens) != 3 {
return ErrUserParse
}
u.Name = tokens[0]
v, err := strconv.ParseInt(tokens[1], 0, strconv.IntSize)
if err != nil {
return err
}
u.age = int(v)
v, err = strconv.ParseInt(tokens[2], 0, strconv.IntSize)
if err != nil {
return err
}
gender := Gender(v)
if !(gender == genderMale || gender == genderFemale) {
return ErrUserParse
}
u.gender = gender
return nil
}
func main() {
var user = User{}
flag.Var(&user, "user", "user information")
flag.Parse()
fmt.Printf("name: %s\n", user.Name)
fmt.Printf("age: %d\n", user.age)
fmt.Printf("gender: %d\n", user.gender)
}
运行
正常解析
$ go run user_defined_flag_type.go --user=xiaoming:18:0
name: xiaoming
age: 18
gender: 0
user 解析失败:信息不足
$ go run user_defined_flag_type.go --user=xiaoming:18
invalid value "xiaoming:18" for flag -user: parse user error
user 解析失败:性别不符
$ go run user_defined_flag_type.go --user=xiaoming:18:2
invalid value "xiaoming:18:2" for flag -user: parse user error
小结
如果要实现自定义的选项类型,则该选项需要实现 flag.Value
接口,关键在于 Set(s string) error
如何实现字符串的解析并将信息转换成类型实例信息。代码。
评论