自己动手写Java虚拟机
上QQ阅读APP看书,第一时间看更新

1.3 编写命令行工具

开发环境已经准备就绪,java命令也已经介绍完毕,相信读者已经迫不及待想开始写代码了吧!下面根据java命令的第一种用法,自己动手编写一个类似的命令行工具。

先定义一个结构体来表示命令行选项和参数。在ch01目录下创建cmd.go文件Go源文件一般以.go作为后缀,文件名全部小写,多个单词之间用下划线分隔。Go语言规范要求Go源文件必须使用UTF-8编码,详见https://golang.org/ref/spec。,用你喜欢的文本编辑器笔者推荐Sublime2,主页为http://www.sublimetext.com/。打开它,然后在其中定义Cmd结构体,代码如下:

package main

import "flag"
import "fmt"
import "os"

type Cmd struct {
helpFlag         bool
versionFlag     bool
cpOption         string
class             string
args              []string
}

在Java语言中,API一般以类库的形式提供。在Go语言中,API则是以包(package)的形式提供。包可以向用户提供常量、变量、结构体以及函数等。Java内置了丰富的类库,Go也同样内置了功能强大的包。本章将用到fmt、os和flag包。

os包定义了一个Args变量,其中存放传递给命令行的全部参数。如果直接处理os.Args变量,需要写很多代码。还好Go语言内置了flag包,这个包可以帮助我们处理命令行选项。有了flag包,我们的工作就简单了很多。继续编辑cmd.go文件,在其中定义parseCmd()函数Go语言有函数(Function)和方法(Method)之分,方法调用需要receiver,函数调用则不需要。,代码如下:

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
}

首先设置flag.Usage变量,把printUsage()函数赋值给它;然后调用flag包提供的各种Var()函数设置需要解析的选项;接着调用Parse()函数解析选项。如果Parse()函数解析失败,它就调用printUsage()函数把命令的用法打印到控制台。printUsage()函数的代码如下:

func printUsage() {
fmt.Printf("Usage: %s [-options] class [args...]\n", os.Args[0])
}

如果解析成功,调用flag.Args()函数可以捕获其他没有被解析的参数。其中第一个参数就是主类名,剩下的是要传递给主类的参数。这样,用了不到40行代码,我们的命令行工具就编写完了。下面来测试它。