flag包

命令源码文件如何接收参数?
Go 语言标准库中有一个代码包专门用于接收和解析命令参数,即flag包。

使用案例

  • 根据运行程序时给定的参数问候某人
package main

import (
	"flag"
	"fmt"
)
var name string
func init() {
	flag.StringVar(&name, "name", "everyone", "the greeting object")
	//flag.StringVar()参数解析:
	//第 1 个参数是用于存储该命令参数的值的地址
	//第 2 个参数是为了指定该命令参数的名称
	//第 3 个参数是为了指定在未追加该命令时的默认参数
	//第 4 个参数是该命令参数的简短说明

	//对比flag.String()
	//这两个函数的区别是,后者会直接返回一个已经分配好的用于存储命令参数值的地址
	//这里使用为var name = flag.String("name", "everyone", "the greeting object")
}
func main() {
	flag.Parse()
	//函数flag.Parse用于真正解析命令参数,并把它们的值赋给相应的变量。
	//对该函数的调用必须在所有命令参数存储载体的声明(这里是对变量name的声明)和设置(这
	//里是指flag.StringVar函数的调用)之后,并且在读取任何命令参数值之前进行。
	//正因为如此,我们最好把flag.Parse()放在main函数的函数体的第一行
	fmt.Printf("Hello, %s!\n", name)
}

执行:
go run learn_flag.go -name="zcm"
输出:
Hello, zcm!

怎样自定义命令源码文件的参数使用说明

方案1:对flag.Usage变量重新赋值

  • 对变量flag.Usage重新赋值。flag.Usage的类型是func(),即一种无参数声明且无结果声明的函数类型
  • flag.Usage变量在声明时就已经被赋值
  • 对flag.Usage的赋值必须在调用flag.Parse函数之前
package main

import (
	"flag"
	"fmt"
	"os"
)
var name string
func init() {
	flag.StringVar(&name, "name", "everyone", "the greeting object")
}
func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
		//当输入 go run main.go --help时,被视为错误命令输入
		flag.PrintDefaults()
	}
	flag.Parse()
	fmt.Printf("Hello, %s!\n", name)
}
输入:
go run learn_flag.go --help
输出:
Usage of question:
  -name string
        the greeting object (default "everyone")
exit status 2

方案2:更深一层,利用flag.CommandLine命令参数容器

  • 我们在调用flag包中的一些函数(比如StringVar、Parse等等)的时候,实际上是在调用flag.CommandLine变量的对应方法。
  • flag.CommandLine相当于默认情况下的命令参数容器。通过对flag.CommandLine重新赋值,可以更深层次地定制当前命令源码文件的参数使用说明
package main

import (
	"flag"
	"fmt"
	"os"
)
var name string
func init() {
	flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError)
	//flag.ExitOnError的含义是,告诉命令参数容器,当命令后跟--help或者参数设置的不正
	//确的时候,在打印命令参数使用说明后以状态码2结束当前程序。
	// 状态码2代表用户错误地使用了命令,而flag.PanicOnError与之的区别是在最后抛出“运
   //行时恐慌(panic)”。上述两种情况都会在我们调用flag.Parse函数时被触发
	flag.CommandLine.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
		flag.PrintDefaults()
	}
	//以上代码必须放在flag.StringVar等参数设置之前
	flag.StringVar(&name, "name", "everyone", "the greeting object")
}
func main() {
	flag.Parse()
	fmt.Printf("Hello, %s!\n", name)
}
输出与方案1一样
若把flag.ExitOnError 改为flag.PanicOnError
在输出解释后,引发panic

创建私有命令参数容器

package main

import (
	"flag"
	"fmt"
	"os"
)
var name string
var cmdLine = flag.NewFlagSet("question", flag.ExitOnError)
func init() {
	cmdLine.StringVar(&name, "name", "everyone", "the greeting object")
}
func main() {
	cmdLine.Parse(os.Args[1:])
	fmt.Printf("Hello, %s!\n", name)
}
  • 不用全局的flag.CommandLine变量,转而自己创建一个私有的命令
    参数容器
  • os.Args[1:]指的就是我们给定的那些命令参数。这样做就完全脱离了
    flag.CommandLine。*flag.FlagSet类型的变量cmdLine拥有很多有意思的方法

其余问题

  • 可以让命令源码文件接受哪些类型的参数值?
    命令源码文件支持的参数:
    int(int|int64|uint|uint64),
    float(float|float64)
    string,
    bool,
    duration(时间),
    var(自定义)

  • 可以把自定义的数据类型作为参数值的类型吗?如果可以,怎样做?
    参数值的类型可以是自定义的数据类型,重点是实现flag包里的Value接口, 然后使用flag.Var()实现。

  • 试着把参数增加到两个,结果是受StringVar声明顺序影响还是受参数传递顺序影响

func init() {
flag.StringVar(&name, "name1", "ladies", "The greeting object 1")
flag.StringVar(&name, "name2", "gentlemen", "The greeting objec t 2")
}
  • go run test.go
    Hello gentlemen !
    name2的默认值覆盖了name1的默认值
  • go run test.go -name1=Robert
    Hello Robert!
    只指定了name1,没有指定name2,输出了name1的指定值,name2的
    默认值没有生效
  • go run test.go -name2=Jose
    Hello Jose!
    没毛病
  • go run test.go -name1=Robert -name2=Jose
    Hello Jose!
    没毛病
  • go run test.go -name2=Jose -name1=Robert
    Hello Robert!
    输出的值是以参数的先后顺序为准的,而不是以flag.StringVar函数的声明顺序为准的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值