- 前言
- Go 与操作系统
- Go 内部机制
- Go 基本数据类型
- 4 组合类型的使用
- 5 数据结构
- 6 Go package 中不为人知的知识
- 7 反射和接口
- 8 Go UNIX 系统编程
- 08.1 关于 UNIX 进程
- 08.2 flag 包
- 8.2 flag 包
- 08.3 io.Reader 和 io.Writer 接口
- 08.4 bufio 包
- 08.5 读取文本文件
- 08.6 从文件中读取所需的数据量
- 08.7 为什么我们使用二进制格式
- 08.8 读取 CSV 文件
- 08.9 写入文件
- 08.10 从磁盘加载和保存数据
- 08.11 再看strings包
- 08.12 关于bytes包
- 08.13 文件权限
- 08.14 处理 Unix 信号
- 08.15 Unix 管道编程
- 08.16 遍历目录树
- 08.17 使用 ePBF
- 08.18 关于 syscall.PtraceRegs
- 08.19 跟踪系统调用
- 08.20 User ID 和 group ID
- 08.21 其他资源
- 08.22 练习
- 08.23 总结
- 9 并发 Goroutines、Channel 和 Pipeline
- 10 Go 并发-进阶讨论
- 11 代码测试、优化及分析
- 12 Go 网络编程基础
- 13 网络编程 - 构建服务器与客户端
8.2 flag 包
标签是被传入程序来控制行为的特殊格式化字符串。如果您想支持多个标签,您自己处理标签可能会非常麻烦。因此,如果您开发 Unix 系统命令行工具的话,如果可替代您会发现 flag
包是非常有趣和有用。它的特点中,flag
包不承担命令行参数和选项的排序,并当执行命令行工具错误时它会打印帮助信息。
flag
包最大的优势是它是 Go 的标准库,这意味着它可有广泛的用于测试和调试。
我将介绍两个使用 flag
包的 Go 程序:一个简单的和一个稍复杂的。
第一个是 simpleFlag.go
,分为四部分。simpleFlag.go
有两个命令行选项:第一个是布尔选项,第二个需要一个整数值。
simpleFlag.go
的第一部分包含如下代码:
package main
import (
"flag"
"fmt"
)
simpleFlag.go
的第二部分如下:
func main(){
minuk := flag.Bool("k", true, "k")
miusO := flag.Int("O", 1, "O")
flag.Parse()
flag.Bool("k", true, "k")
语句定义了一个名为 k
默认值伪 true
的布尔值命令选项。该语句最后的参数是作为程序的使用信息来显示的。同样,flag.Int()
函数增加整数命令选项支持。
您总是要在定义了您想要的命令行选项后调用
flag.Parse()
simpleFlag.go
的第三段代码如下:
valueK := *minusK
valueO := *minusO
valueO++
从上面的代码您可以看到您可以获取到选项值。在这里 flag
包自动把分配给 flag.Int()
标签的输入值转为整数值。这意味着您不必自己做。另外,flag
包确保分配了一个可接受的整数值。
simpleFlag.go
的其余代码如下:
fmt.Println("-k:", valueK)
fmt.Println("-O:", valueO)
}
在获得期望的参数后,您现在就可以使用它们了。
执行 simpleFlag.go
产生如下输出:
$go run simpleFlag.og -O 100
-k: true
-O: 101
$go run simpleFlag.og -O=100
-k: true
-O: 101
$go run simpleFlag.og -O=100 -k
-k: true
-O: 101
$go run simpleFlag.og -O=100 -k false
-k: true
-O: 101
$go run simpleFlag.og -O=100 -k=false
-k: true
-O: 101
如果执行 simpleFlag.go
发生错误时,您会看到如下的错误信息:
$go rum simpleFlag.go -O=notAnInterger
invalid value "ontAnInteger" for lag -O: strconv.ParseInt: parsing "notAnInteger": invalid syntax
Usage of /var/folders/sk/ltk8cnw501zdtr2hxcj5sv2m0000gn/T/go-build020625525/command-line arguments/_obj/exe/simpleFlag:
-O int
O (default 1)
-k k (default true)
exit status 2
注意这个方便的使用信息是当您的程序输入了错误的命令行选项时自动打印的。
现在是时候介绍一个更实际和复杂点的使用 flag
包的程序了——funWithFlag.go
,分为五部分来介绍。funWithFlag.go
有各种选项,包括一个可以接收用逗号分隔的多值选项。另外,它会说明您如果能够访问位于执行程序末尾并不属于任何选项的命令行参数。
flag.Var()
函数在 funWithFlag.go
中用于创建一个实现了 flag.Value
接口的任意类型的标签,该接口定义如下:
type Value interface {
String() string
Set(string) error
}
funWithFlag.go
的第一部分如下:
package main
import(
"flag"
"fmt"
"strings"
)
type NamesFlag struct {
Names []string
}
NamesFlag
数据结构用于 flag.Value
接口。
funWithFlag.go
的第二部分如下:
func (s *NamesFlag) GetNames() []string{
return s.Names
}
func (s *NamesFlag) String() string {
return fmt.Sprint(s.Names)
}
funWithFlag.go
的第三部分代码如下:
func (s *NamesFlag) Set(v string) error {
if len(s.Names) > 0 {
return fmt.Errorf("Cannot use names flag more than once!")
}
names := strings.Split(v, ",")
for _, item := range names {
s.Names = append(s.Names, item)
}
return nil
}
首先,Set()
方法确保相关命令行选项没有被设置。之后,获取输入并使用 strings.Split()
函数来分隔参数。最后,参数被保存在 NamesFlag
结构的 Names
字段。
funWithFlag.go
的第四部分代码如下:
func main() {
var manyNames NamesFlag
minusK := flag.Int("k:", 0, "An int")
minusO := flag.String("o", "Mihalis", "The name")
flag.Var(&manyNames, "names", "Comma-separated list")
flag.Parse()
fmt.Println("-k:", *minusK)
fmt.Println("-o:", *minusO)
funWithFlag.go
的最后部分如下:
for i, item := range manyNames.GetNames() {
fmt.Println(i, item)
}
fmt.Println("Remaing command-line arugments:")
for index, val := range flag.Args() {
fmt.Println(index, ":", val)
}
}
flag.Args()
切片保留命令行参数,而 manyNames
变量保留来自 flag.Var()
命令行选项的值。
执行 funWithFlag.go
产生如下输出:
除非您开发一个不需要选项的命令行小工具,否则您极需要使用
flag
包来处理您的程序的命令行选项。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论