diff --git a/ch1/ch1-02.md b/ch1/ch1-02.md index 5d8e473..9874db9 100644 --- a/ch1/ch1-02.md +++ b/ch1/ch1-02.md @@ -1,6 +1,6 @@ ## 1.2. 命令行参数 -大多数的程序都是处理输入,产生输出;这也正是 “计算” 的定义。但是,程序如何获取要处理的输入数据呢?一些程序生成自己的数据,但通常情况下,输入来自于程序外部:文件、网络连接、其它程序的输出、敲键盘的用户、命令行参数或其它类似输入源。下面几个例子会讨论其中几个输入源,首先是命令行参数。 +大多数的程序都是处理输入,产生输出;这也正是“计算”的定义。但是,程序如何获取要处理的输入数据呢?一些程序生成自己的数据,但通常情况下,输入来自于程序外部:文件、网络连接、其它程序的输出、敲键盘的用户、命令行参数或其它类似输入源。下面几个例子会讨论其中几个输入源,首先是命令行参数。 `os` 包以跨平台的方式,提供了一些与操作系统交互的函数和变量。程序的命令行参数可从 `os` 包的 `Args` 变量获取;`os` 包外部使用 `os.Args` 访问该变量。 @@ -11,6 +11,7 @@ 下面是 Unix 里 `echo` 命令的一份实现,`echo` 把它的命令行参数打印成一行。程序导入了两个包,用括号把它们括起来写成列表形式,而没有分开写成独立的 `import` 声明。两种形式都合法,列表形式习惯上用得多。包导入顺序并不重要;`gofmt` 工具格式化时按照字母顺序对包名排序。(示例有多个版本时,我们会对示例编号,这样可以明确当前正在讨论的是哪个。) gopl.io/ch1/echo1 + ```go // Echo1 prints its command-line arguments. package main @@ -34,33 +35,17 @@ func main() { `var` 声明定义了两个 `string` 类型的变量 `s` 和 `sep`。变量会在声明时直接初始化。如果变量没有显式初始化,则被隐式地赋予其类型的 *零值*(zero value),数值类型是 `0`,字符串类型是空字符串 `""`。这个例子里,声明把 `s` 和 `sep` 隐式地初始化成空字符串。第 2 章再来详细地讲解变量和声明。 -对数值类型,Go 语言提供了常规的数值和逻辑运算符。而对 `string` 类型,`+` 运算符连接字符串(译注:和 C++ 或者 JavaScript 是一样的)。所以表达式: - -```go -sep + os.Args[i] -``` - -表示连接字符串 `sep` 和 `os.Args`。程序中使用的语句: - -```go -s += sep + os.Args[i] -``` - -是一条 *赋值语句*,将 `s` 的旧值跟 `sep` 与 `os.Args[i]` 连接后赋值回 `s`,等价于: - -```go -s = s + sep + os.Args[i] -``` +对数值类型,Go 语言提供了常规的数值和逻辑运算符。而对 `string` 类型,`+` 运算符连接字符串(译注:和 C++ 或者 JavaScript 是一样的)。所以表达式:`sep + os.Args[i]` 表示连接字符串 `sep` 和 `os.Args`。程序中使用的语句:`s+=sep+os.Args[i]` 是一条 *赋值语句*,将 `s` 的旧值跟 `sep` 与 `os.Args[i]` 连接后赋值回 `s`,等价于:`s=s+sep+os.Args[i]`。 运算符 `+=` 是赋值运算符(assignment operator),每种数值运算符或逻辑运算符,如 `+` 或 `*`,都有对应的赋值运算符。 `echo` 程序可以每循环一次输出一个参数,这个版本却是不断地把新文本追加到末尾来构造字符串。字符串 `s` 开始为空,即值为 `""`,每次循环会添加一些文本;第一次迭代之后,还会再插入一个空格,因此循环结束时每个参数中间都有一个空格。这是一种二次加工(quadratic process),当参数数量庞大时,开销很大,但是对于 `echo`,这种情形不大可能出现。本章会介绍 `echo` 的若干改进版,下一章解决低效问题。 -循环索引变量 `i` 在 for 循环的第一部分中定义。符号 `:=` 是 *短变量声明*(short variable declaration)的一部分,这是定义一个或多个变量并根据它们的初始值为这些变量赋予适当类型的语句。下一章有这方面更多说明。 +循环索引变量 `i` 在 `for` 循环的第一部分中定义。符号 `:=` 是 *短变量声明*(short variable declaration)的一部分,这是定义一个或多个变量并根据它们的初始值为这些变量赋予适当类型的语句。下一章有这方面更多说明。 -自增语句 `i++` 给 `i` 加 1;这和 `i+=1` 以及 `i=i+1` 都是等价的。对应的还有 `i--` 给 `i` 减 1。它们是语句,而不像 C 系的其它语言那样是表达式。所以 `j=i++` 非法,而且 `++` 和 `--` 都只能放在变量名后面,因此 `--i` 也非法。 +自增语句 `i++` 给 `i` 加 `1`;这和 `i+=1` 以及 `i=i+1` 都是等价的。对应的还有 `i--` 给 `i` 减 `1`。它们是语句,而不像 C 系的其它语言那样是表达式。所以 `j=i++` 非法,而且 `++` 和 `--` 都只能放在变量名后面,因此 `--i` 也非法。 -Go 语言只有 for 循环这一种循环语句。for 循环有多种形式,其中一种如下所示: +Go 语言只有 `for` 循环这一种循环语句。`for` 循环有多种形式,其中一种如下所示: ```go for initialization; condition; post { @@ -68,7 +53,7 @@ for initialization; condition; post { } ``` -for 循环三个部分不需括号包围。大括号强制要求,左大括号必须和 *`post`* 语句在同一行。 +`for` 循环三个部分不需括号包围。大括号强制要求,左大括号必须和 *`post`* 语句在同一行。 *`initialization`* 语句是可选的,在循环开始前执行。*`initalization`* 如果存在,必须是一条 *简单语句*(simple statement),即,短变量声明、自增语句、赋值语句或函数调用。`condition` 是一个布尔表达式(boolean expression),其值在每次循环迭代开始时计算。如果为 `true` 则执行循环体语句。`post` 语句在循环体执行结束后执行,之后再次对 `condition` 求值。`condition` 值为 `false` 时,循环结束。 @@ -95,6 +80,7 @@ for { `for` 循环的另一种形式,在某种数据类型的区间(range)上遍历,如字符串或切片。`echo` 的第二版本展示了这种形式: gopl.io/ch1/echo2 + ```go // Echo2 prints its command-line arguments. package main @@ -134,6 +120,7 @@ var s string = "" 如果连接涉及的数据量很大,这种方式代价高昂。一种简单且高效的解决方案是使用 `strings` 包的 `Join` 函数: gopl.io/ch1/echo3 + ```go func main() { fmt.Println(strings.Join(os.Args[1:], " ")) @@ -154,4 +141,4 @@ fmt.Println(os.Args[1:]) **练习 1.2:** 修改 `echo` 程序,使其打印每个参数的索引和值,每个一行。 -**练习 1.3:** 做实验测量潜在低效的版本和使用了 `strings.Join` 的版本的运行时间差异。(1.6 节讲解了部分 `time` 包,11.4 节展示了如何写标准测试程序,以得到系统性的性能评测。) +**练习 1.3:** 做实验测量潜在低效的版本和使用了 `strings.Join` 的版本的运行时间差异。([1.6 节](./ch1-06.md)讲解了部分 `time` 包,[11.4 节](../ch11/ch11-04.md)展示了如何写标准测试程序,以得到系统性的性能评测。)