需求描述
需要使用Go语言实现一个可以在控制台输入命令和参数即可运行的程序。
比如(其中的一条命令):给公链上添加区块,但是区块上的data需要在执行命令行时指定(也就是说我们所执行的命令需要调用一个方法,这个方法还需要传入一个data数据)
flag简单用法
flag的简单用法这里就省略了,大家如果想从这里学就发评论给我,有时间我就把它更新了。
..........................
代码实现
根据需求实现的代码如下:
其实这里实现的有三个命令:
-
创建区块链 (createblockchain)
-
添加区块(addblock -data Data)
-
输出区块链信息(printchain)
// Run 客户端运行的主体方法
func (cli *Cli) Run() {
// 创建区块链的命令
createBlockChainCmd := flag.NewFlagSet("createblockchain", flag.ExitOnError)
// 输出区块链的命令
printChainCmd := flag.NewFlagSet("printchain", flag.ExitOnError)
// 添加区块的命令
addBlockCmd := flag.NewFlagSet("addblock", flag.ExitOnError)
addBlockArgs := addBlockCmd.String("data", "默认数据,错误区块", "-data 后输入数据")
fmt.Printf("addBlockArgs: %v\n", &addBlockArgs)
// 判断用户的输入
switch os.Args[1] {
case "createblockchain":
// 创建区块链
// 检测用户的输入
err := createBlockChainCmd.Parse(os.Args[2:])
errLog(err, "命令 createblockchain 错误")
case "addblock":
// 添加区块
// 检测用户输入
err := addBlockCmd.Parse(os.Args[2:])
errLog(err, "命令 addblock 错误")
case "printchain":
// 打印区块链
// 检测用户输入
err := printChainCmd.Parse(os.Args[2:])
errLog(err, "命令 printchain 错误")
default:
// 用户无输入或输入错误时打印用法并退出
PrintUsage()
os.Exit(1)
}
// 创建区块链
if createBlockChainCmd.Parsed() {
createblockchain()
}
// 添加区块
if addBlockCmd.Parsed() {
// 检测是否有输入
if *addBlockArgs == "" {
PrintUsage()
os.Exit(1)
}
cli.addblock(*addBlockArgs)
}
// 打印区块链信息
if printChainCmd.Parsed() {
printchain()
}
}
主程序代码如下:
// 启动
func main() {
var cli BLC.Cli
cli.Run()
}
这里需要注意的是“添加区块的命令”,这个命令后需要带参数所以这里的写法是:
// 添加区块的命令
addBlockCmd := flag.NewFlagSet("addblock", flag.ExitOnError)
addBlockArgs := addBlockCmd.String("data", "默认数据,错误区块", "-data 后输入数据")
“addBlockArgs” 这个参数定义是在 "addBlockCmd"的基础上,千万不能写成下面这样:
addBlockArgs := flag.String("data", "默认数据,错误区块", "-data 后输入数据")
这个是以flag为主体的参数,是main.exe 后面紧跟的参数
控制台正确输入
先编译程序:
go build -o blockChain.exe main.exe
执行我们需求中提到的命令:
blockChain.exe addblockchain -data 123
如果想输入的数据中间有空格,需要给数据部分带上双引号,如下:
blockChain.exe addblockchain -data "this is new block"
注意
主程序后的第一个命令或参数是不允许出现“-”、“--”及“=”,源码如下:
// Var defines a flag with the specified name and usage string. The type and
// value of the flag are represented by the first argument, of type Value, which
// typically holds a user-defined implementation of Value. For instance, the
// caller could create a flag that turns a comma-separated string into a slice
// of strings by giving the slice the methods of Value; in particular, Set would
// decompose the comma-separated string into the slice.
func (f *FlagSet) Var(value Value, name string, usage string) {
// Flag must not begin "-" or contain "=".
if strings.HasPrefix(name, "-") {
panic(f.sprintf("flag %q begins with -", name))
} else if strings.Contains(name, "=") {
panic(f.sprintf("flag %q contains =", name))
}
...
}
这是go语言底层在解析控制台输入时的校验