注:命令源码文件:如果一个源码文件声明属于main包,并且包含一个无参数声明的main函数,那么他就是命令源码文件。
将代码拆分到多个文件,甚至拆分到不同的代码包中。但是,命令源文件永远只有一个,也就是只有一个main函数入口。
如果有与命令源文件同包的源码文件,那么他们也应该声明属于main包(package main)
-
1.命令源码文件怎样接收参数
知识点:Go标准库中,有一个flag库专门用于接受和解析命令参数。
其中StringVar函数用来接受字符串参数,String函数直接返回已经分配好的用于存储命令参数值的地址,用法不同:
flag.StringVar(&name, "name", ...)
flag.String("name", ...)
这里使用StringVar函数处理,示例,demo2.go
// demo2.go
package main
import (
"flag"
"fmt"
)
var StudentName string
//初始化函数,编译时自动调用
func init() {
flag.StringVar(&StudentName,
"name", "Default Name",
"This is student depart \ndescription.")
}
func main() {
flag.Parse() // 解析命令参数,并把值赋给变量 StudentName
fmt.Printf("Hello, %s!\n", StudentName)
}
说明一下StringVar函数的参数列表:
第一个参数是用于存储该命令参数的值的地址,用符号“&”表示,这里取“&StudentName”
第二个参数指定了该命令参数的名称,这里是“name”,使用方法“-name”
第三个参数指定了未追加该命令参数时的默认值,这里是“Default Name”
第四个参数指的是该命令参数的描述
-
2.怎样在运行命令源码文件时传参,查看参数使用说明
上述文件报存为demo2.go,在运行如下命令就可以为参数name传值:
go run demo2.go -name="Steven"
运行结果:
$ go run demo2.go -name="Steven"
Hello, Steven!
前面提到过第四个参数为参数说明,可以运行“--help”查看,比如: go run demo2.go --help
go run demo2.go --help
Usage of /tmp/go-build084670678/b001/exe/demo2:
-name string
This is student depart
description. (default "Default Name")
exit status 2
其中有一段输出“/tmp/go-build084670678/b001/exe/demo2”, 指的是 go run 命令构建源码文件时生成的临时文件的完整路径。
接下来,我们可以构建(build)源码文件,并生成可执行文件了,比如:
[root@localhost example]# go build demo2.go
[root@localhost example]# ./demo2 --help
那么输出就会是:
Usage of ./demo2:
-name string
This is student depart
description. (default "Default Name")
试着把参数增加到两个试试运行结果:
-
3.怎样自定义命令源码文件的参数使用说明
知识点:flag.Usage的类型是func(),是一种无参数声明且无结果声明的函数类型,也可以作为变量,它在声明时就被赋值。
如果要自定义参数使用说明,对flag.Usage的赋值就必须在flag.Parse前。
下面来看示例,demo3.go(注意要导入os库):
-
// demo3.go
-
package main
-
import (
-
"flag"
-
"fmt"
-
"os"
-
)
-
var StudentName string
-
//初始化函数,编译时自动调用
-
func init() {
-
flag.StringVar(&StudentName,
-
"name", "Default Name",
-
"This is student depart \ndescription.")
-
}
-
func main() {
-
flag.Usage = func() {
-
fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
-
flag.PrintDefaults()
-
}
-
flag.Parse()
-
fmt.Printf("Hello, %s!\n", StudentName)
-
}
运行后,会发现代替了之前的输出:
-
[root@localhost example]# go run demo3.go --help
-
Usage of question:
-
-name string
-
This is student depart
-
description. (default "Default Name")
-
exit status 2
知识点:flag.CommandLine变量也是一种func()类型,当我们在调用StringVar,Parse时,其实就是在调用该变量的对应方法,其就相当于默认情况下的命令参数“容器”。
下面,我们再次来实践下,demo3-1.go:
-
// demo3-1.go
-
package main
-
import (
-
"flag"
-
"fmt"
-
"os"
-
)
-
var StudentName string
-
//初始化函数,编译时自动调用
-
func init() {
-
flag.StringVar(&StudentName,
-
"name", "Default Name",
-
"This is student depart \ndescription.")
-
}
-
func main() {
-
flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError)
-
flag.CommandLine.Usage = func() {
-
fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
-
flag.PrintDefaults()
-
}
-
flag.Parse()
-
fmt.Printf("Hello, %s!\n", StudentName)
-
}
这样的定制方式更灵活,还可以改为:
flag.CommandLine=flag.NewFlagSet("", flag.PanicOnError)
其中flag.PanicOnError和flag.ExitOnError都是预定义在flag包中的常量。
ExitOnError告诉命令参数容器,如果参数设置不正确的时候,以状态码2(表示用户使用了错误的命令)结束当前程序。
PanicOnError指的是最后抛出“运行时恐慌(panic)-一种Go语言在程序错误处理方面的概念”。
接下来,我们采用自己创建一个私有的命令参数“容器”,在main函数外先增加一个变量声明:
-
// demo3-2.go
-
package main
-
import (
-
"flag"
-
"fmt"
-
"os"
-
)
-
var StudentName string
-
var cmdLine = flag.NewFlagSet("question", flag.ExitOnError)
-
//初始化函数,编译时自动调用
-
func init() {
-
cmdLine.StringVar(&StudentName,
-
"name", "Default Name",
-
"This is student depart \ndescription.")
-
}
-
func main() {
-
flag.CommandLine = flag.NewFlagSet("", flag.PanicOnError)
-
flag.CommandLine.Usage = func() {
-
fmt.Fprintf(os.Stderr, "Usage of %s:\n", "question")
-
flag.PrintDefaults()
-
}
-
cmdLine.Parse(os.Args[1:]) // 接受的参数
-
fmt.Printf("Hello, %s!\n", StudentName)
-
}
在demo3-3例子中,完全脱离了flag.CommandLine变量,也就是说无论如何都不会影响到该变量,这样就更灵活了。
-
4.问题
1.默认情况下,我们可以让命令源码文件接受哪些类型的参数值?
答:string,bool,int三种类型
2.我们可以把自定义的数据类型作为参数值的类型吗?如果可以,怎样做?
答:使用func Set(myset,value string) error 等定义一个类型,var myflag myset定义变量,flag.Var(&myflag, ‘default value’, ‘doc’)