如果你看过《深入理解计算机系统》,对计算机世界有一定认识的话,一定知道对于操作系统来讲,一切皆文件。大部分的程序都是在不同的文件之间处理数据。对于程序来讲,数据有输入有输出,有的输入来自程序自身产生,而大部分的输入来自另外一个文件:文件、网络连接、其他程序输出、键盘、命令行参数等。
今天讨论的就是,我们如何通过命令行,来给我们的Go程序输入数据!
一、借助os包实现
其实在 Hello World! 这一节中,我们已经见到了os.Args变量,混了个眼熟。那么在这里,大家可以根据下面提供的例子感受借助os.Args变量从命令行中获取参数并输出出来。
os包以跨平台的方式,提供了一些与操作系统交互相关的函数和变量。程序的命令行参数可从os包的Args变量获取;os包外部使用os.Args访问该变量。
os.Args变量是一个字符串(string)的切片(slice)。用s[i]访问单个元素,用s[m:n]获取子序列。在Go语言中,所有的索引使用半开区间,即包含第一个索引,不包含最后一个索引。这样可以简化逻辑。(这个其实也很好理解,是为了顺应数组下标从0开始,且不包含数组长度值的那个索引。所以很方便的就可以通过 s[0:len(s)]来得到子串,避免了非必要的计算)
os.Args的第一个元素:os.Args[0],是命令本身的名字;其它的元素则是程序启动时传给它的参数。
大家可以提供下面的例子感受借助os.Args变量从命令行中获取参数并输出出来。
// Echo1 prints its command-line arguments.
package main
import (
"fmt"
"os"
)
func main() {
var s, sep string
for i := 1; i < len(os.Args); i++ {
s += sep + os.Args[i]
sep = " "
}
fmt.Println(s)
}
我们先简单的理解下上面这段程序,至于里面详细的内容,后面的指定章节会有详细讲解。
- 注释语句以//开头,//之后到行末之间所有的内容都是注释,被编译器忽略。按照惯例,我们在每个包的包声明前添加注释;
- 程序用import命令导入了两个包,用括号把它们括起来写成列表形式。包导入顺序并不重要;gofmt工具格式化时按照字母顺序对包名排序;
- var声明定义了两个string类型的变量s和sep。变量会在声明时直接初始化。如果变量没有显式初始化,则被隐式地赋予其类型的零值(zero value),数值类型是0,字符串类型是空字符串"";实践中一般使用前两种形式中的某个,初始值重要的话就显式地指定变量的类型,否则使用隐式初始化。
- 对数值类型,Go语言提供了常规的数值和逻辑运算符,如i++,但++i非法。而对string类型,+运算符连接字符串;运算符+=是赋值运算符;
- for循环三个部分不需括号包围。大括号强制要求,左大括号必须和post语句在同一行;for循环的另一种形式,在某种数据类型的区间(range)上遍历,如字符串或切片;
for _, arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
func main() {
fmt.Println(strings.Join(os.Args[1:], " "))
}
好了,通过命令行操作在这一节,我们再一次体验了Go程序的一些特性,在后面的章节中我们会一一详细道来,你准备好接招了吗?