编写命令行工具
编写命令行工具
环境准备完毕,接下来实现java
命令的的第一种用法。
创建目录

创建cmd.go
Go源文件一般以.go作为后缀,文件名全部小写,多个单词之间使用下划线分隔。Go语言规范要求Go源文件必须使用UTF-8编码,详见https://golang.org/ref/spec
结构体存储cmd选项
在文件中定义cmd中java命令需要的选项和参数
package ch01
// author:郜宇博
type Cmd struct {
// 标注是否为 --help
helpFlag bool
//标注是否为 --version
versionFlag bool
//选项
cpOption string
//主类名,或者是jar文件
class string
//参数
args []string
}
Go语言标准库包
由于要处理的命令行,因此将使用到flag()
函数,此函数为Go的标准库包之一。
Go语言的标准库以包的方式提供支持,下表列出了Go语言标准库中常见的包及其功能。
Go语言标准库包名 | 功 能 |
---|---|
bufio | 带缓冲的 I/O 操作 |
bytes | 实现字节操作 |
container | 封装堆、列表和环形列表等容器 |
crypto | 加密算法 |
database | 数据库驱动和接口 |
debug | 各种调试文件格式访问及调试功能 |
encoding | 常见算法如 JSON、XML、Base64 等 |
flag | 命令行解析 |
fmt | 格式化操作 |
go | Go语言的词法、语法树、类型等。可通过这个包进行代码信息提取和修改 |
html | HTML 转义及模板系统 |
image | 常见图形格式的访问及生成 |
io | 实现 I/O 原始访问接口及访问封装 |
math | 数学库 |
net | 网络库,支持 Socket、HTTP、邮件、RPC、SMTP 等 |
os | 操作系统平台不依赖平台操作封装 |
path | 兼容各操作系统的路径操作实用函数 |
plugin | Go 1.7 加入的插件系统。支持将代码编译为插件,按需加载 |
reflect | 语言反射支持。可以动态获得代码中的类型信息,获取和修改变量的值 |
regexp | 正则表达式封装 |
runtime | 运行时接口 |
sort | 排序接口 |
strings | 字符串转换、解析及实用函数 |
time | 时间接口 |
text | 文本模板及 Token 词法器 |
flag()函数
eg:flag.TypeVar()
基本格式如下: flag.TypeVar(Type指针, flag名, 默认值, 帮助信息)
例如我们要定义姓名、年龄、婚否三个命令行参数,我们可以按如下方式定义:
var name string
var age int
var married bool
var delay time.Duration
flag.StringVar(&name, "name", "张三", "姓名")
flag.IntVar(&age, "age", 18, "年龄")
flag.BoolVar(&married, "married", false, "婚否")
flag.DurationVar(&delay, "d", 0, "时间间隔")
接收处理用户输入的命令行指令
创建parseCmd()函数,实现接受处理用户输入的命令行指令
func parseCmd() *Cmd {
cmd := &Cmd{}
flag.Usage = printUsage
flag.BoolVar(&cmd.helpFlag, "help", false, "print help message")
flag.BoolVar(&cmd.helpFlag, "?", false, "print help message")
flag.BoolVar(&cmd.versionFlag, "version", false, "print version and exit")
flag.StringVar(&cmd.cpOption, "classpath", "", "classpath")
flag.StringVar(&cmd.cpOption, "cp", "", "classpath")
flag.Parse()
args := flag.Args()
if len(args) > 0 {
cmd.class = args[0]
cmd.args = args[1:]
}
return cmd
}
func printUsage() {
fmt.Printf("Usage: %s [-options] class [args...]\n", os.Args[0])
//flag.PrintDefaults()
}
首先设置flag.Usage
变量,把printUsage()
函数赋值给它; 然后调 用flag包提供的各种Var函数设置需要解析的选项; 接着调用 Parse()
函数解析选项。
如果Parse()
函数解析失败,它就调用 printUsage()
函数把命令的用法打印到控制台。
如果解析成功,调用flag.Args()
函数可以捕获其他没有被解析 的参数。其中第一个参数就是主类名,剩下的是要传递给主类的参数。
测试
与cmd.go文件一样,main.go文件的包名也是main。在Go 语言中,main是一个特殊的包,这个包所在的目录(可以叫作任何 名字)会被编译为可执行文件。Go程序的入口也是main()函数,但 是不接收任何参数,也不能有返回值。
测试代码如下:
package main
import "fmt"
func main() {
cmd := parseCmd()
if cmd.versionFlag {
//模拟输出版本
fmt.Println("version 0.0.1")
} else if cmd.helpFlag || cmd.class == "" {
printUsage()
} else {
startJVM(cmd)
}
}
// 模拟启动JVM
func startJVM(cmd *Cmd) {
fmt.Printf("classpath:%s class:%s args:%v\n",
cmd.cpOption, cmd.class, cmd.args)
}
main()
函数先调用ParseCommand()
函数解析命令行参数,如 果一切正常,则调用startJVM()
函数启动Java虚拟机。如果解析出现错误,或者用户输入了-help选项,则调用PrintUsage()
函数打印出帮助信息。如果用户输入了-version
选项,则输版本信息。因为我们还没有真正开始编写Java虚拟机,所以startJVM()
函数暂时只是打印一些信息而已。
在终端:
go install jvmgo\ch0
此时在工作空间的bin目录中会生成ch01.exe的文件,运行:结果如下

