用 flag 包做参数获取
刚开始学习用 Go 语言来做小工具,没想到就碰到了个大问题,就是后面有些难理解 (´;ω;`)
使用 flag 包可以用来实现从命令行获取参数的效果
比如 pacmman -S
这样的效果
普通用法
普通用法就是最基本的实现,没有什么花里胡哨的
1 2 3 4 5 6 7
| func main() { var name string flag.StringVar(&name, "name", "Let's go~~~", "help") flag.StringVar(&name, "n", "Let's go!!!", "help") flag.Parse() fmt.Printf("name= %s\n", name) }
|
flag.StringVar(&name, "name", "Let's go~~~", "help")
参数注册,给变量 name 绑定了一个 name 的名字,第三个参数是它的默认值,第四个描述它是干什么的.有两行说明用参数 name 和 n 都可以找到变量 name
flag.Parse()
用来解析并绑定命令行参数,必须在所有参数注册后,使用前调用
命令行执行效果
1 2 3
| go run main.go -name=nero // 结果: name= nero go run main.go -n=nero // 结果: name= nero go run main.go // 结果: name= Let's go!!!
|
子命令用法
子命令就是给命令分级,一层一层的选择命令
比如 go run
和 go get
run 和 get 就是两个子命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func main() { var name string flag.Parse() runCmd := flag.NewFlagSet("run", flag.ExitOnError) runCmd.StringVar(&name, "name", "run run run", "help") dashCmd := flag.NewFlagSet("dash", flag.ExitOnError) dashCmd.StringVar(&name, "n", "dash dash dash", "help")
args := flag.Args() if len(args) <= 0 { return }
switch args[0] { case "run": _ = runCmd.Parse(args[1:]) case "dash": _ = dashCmd.Parse(args[1:]) } fmt.Printf("name= %s\n", name) }
|
flag.NewFlagSet("run", flag.ExitOnError)
创建一个子命令集名为 run,异常情况会返回错误 os.Exit(2),详情查看 https://pkg.go.dev/flag#ErrorHandling
args := flag.Args()
返回参数列表
runCmd.Parse(args[1:])
原方法为 func (*FlagSet) Parse 表示从参数列表中解析标志定义,对解析方法的进一步封装,实际解析逻辑交由 parseOne
命令执行效果
1 2
| go run main.go run -name=nero // 结果: name= nero go run main.go dash -n=nero // 结果: name= nero
|
高级用法
flag 的运行逻辑大概是这样的:
flag.Parse 解析并绑定命令 –> FlagSet.Parse 对解析方法的进一步封装,交由 FlagSet.parseOne 逻辑解析 –> FlagSet.parseOne 先对参数的规则进行校验,没问题了就会使用该 flag 提供的 Value.Set 来实现对应的动作
注意是该 flag 的 Value.Set 方法,意思是说我们可以自定义这个方法
为了实现高级用法,就要我们自己实现 Value 接口里的所有方法:
1 2 3 4
| type Value interface { String() string Set(string) error }
|
其中 String() 方法是运行中如果没有带参数,就会运行它,原文介绍 https://pkg.go.dev/flag#Value
flag 包可以调用带有零值接收器的 String 方法,例如 nil 指针
而 Set() 方法就是碰到什么命令时该做什么
value 就是我们传入的参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| type Name string
func (i *Name) String() string { *i = "Default is me~" return fmt.Sprint(*i) }
func (i *Name) Set(value string) error { if value == "hello" { *i = "world" return nil } *i = Name("Go tour hajimaliyo~ " + value) return nil }
func main() { var name Name flag.Var(&name, "name", "help") flag.Parse() fmt.Println(name) }
|
命令行执行效果
1 2 3
| go run main.go // 结果: default is me~ go run main.go -name=nero // 结果: Go tour hajimaliyo~ go run main.go -name=hello // 结果: world
|
如此看来,如果想要用高级用法,只需要实现接收参数的变量的 Value 的结果就可以了
看上去没多少,但是却花了为2个小时看文档,找实例用法,总算是理解了个大概 ( º﹃º )
算是解决了个问题吧,能睡个好觉了 ΩДΩ