回到简体

This commit is contained in:
chai2010
2016-02-15 11:06:34 +08:00
parent 9e878f9944
commit 2b37b23285
177 changed files with 2354 additions and 2354 deletions

View File

@@ -1,14 +1,14 @@
## 1.2. 命令行參數
## 1.2. 命令行参数
大多的程序都是處理輸入,産生輸出;也正是“算”的定。但是, 程序如何取要理的輸入數據呢?一些程序生成自己的數據,但通常情下,輸入來自於程序外部:文件、網絡連接、其它程序的出、敲鍵盤的用、命令行參數或其它類似輸入源。下面幾個例子會討論其中幾個輸入源,首先是命令行參數
大多的程序都是处理输入,产生输出;也正是“算”的定。但是, 程序如何取要理的输入数据呢?一些程序生成自己的数据,但通常情下,输入来自于程序外部:文件、网络连接、其它程序的出、敲键盘的用、命令行参数或其它类似输入源。下面几个例子会讨论其中几个输入源,首先是命令行参数
`os`包以跨平台的方式,提供了一些操作繫統交互的函數和變量。程序的命令行參數可從os包的Args變量獲os包外部使用os.Args訪問該變量。
`os`包以跨平台的方式,提供了一些操作系统交互的函数和变量。程序的命令行参数可从os包的Args变量获os包外部使用os.Args访问该变量。
os.Args量是一字符串string的*切片*slice譯註slice和Python言中的切片似,是一個簡版的動態數組切片是Go言的基概念,稍後詳細介紹。現在先把切片s當作數組元素序列, 序列的成長度動態變化, 用`s[i]`訪問單個元素,用`s[m:n]`取子序列(譯註和python里的法差不多)。序列的元素數目爲len(s)。和大多數編程語言類似,區間索引Go言里也采用左閉右開形式, 卽,區間包括第一索引元素,不包括最後一個, 因爲這樣可以簡化邏輯。(譯註比如a = [1, 2, 3, 4, 5], a[0:3] = [1, 2, 3],不包含最後一個元素。比如s[m:n]這個切片0 ≤ m ≤ n ≤ len(s)包含n-m元素。
os.Args量是一字符串string的*切片*slice译注slice和Python言中的切片似,是一个简版的动态数组切片是Go言的基概念,稍后详细介绍。现在先把切片s当作数组元素序列, 序列的成长度动态变化, 用`s[i]`访问单个元素,用`s[m:n]`取子序列(译注和python里的法差不多)。序列的元素数目为len(s)。和大多数编程语言类似,区间索引Go言里也采用左闭右开形式, 即,区间包括第一索引元素,不包括最后一个, 因为这样可以简化逻辑。(译注比如a = [1, 2, 3, 4, 5], a[0:3] = [1, 2, 3],不包含最后一个元素。比如s[m:n]这个切片0 ≤ m ≤ n ≤ len(s)包含n-m元素。
os.Args的第一元素os.Args[0], 是命令本身的名字;其它的元素是程序啟動時傳給它的參數。s[m:n]形式的切片表式,産生從第m元素到第n-1元素的切片,下例子用到的元素包含在os.Args[1:len(os.Args)]切片中。如果省略切片表式的m或n會默認傳入0或len(s),因此前面的切片可以簡寫成os.Args[1:]。
os.Args的第一元素os.Args[0], 是命令本身的名字;其它的元素是程序启动时传给它的参数。s[m:n]形式的切片表式,产生从第m元素到第n-1元素的切片,下例子用到的元素包含在os.Args[1:len(os.Args)]切片中。如果省略切片表式的m或n会默认传入0或len(s),因此前面的切片可以简写成os.Args[1:]。
下面是Unix里echo命令的一份實現echo把它的命令行參數打印成一行。程序入了兩個包,用括把它括起來寫成列表形式, 而有分開寫成獨立的`import`明。兩種形式都合法,列表形式習慣上用得多。包導入順序併不重要gofmt工具格式化按照字母順序對包名排序。(示例有多版本,我們會對示例編號, 這樣可以明確當前正在討論的是哪。)
下面是Unix里echo命令的一份实现echo把它的命令行参数打印成一行。程序入了两个包,用括把它括起来写成列表形式, 而有分开写成独立的`import`明。两种形式都合法,列表形式习惯上用得多。包导入顺序并不重要gofmt工具格式化按照字母顺序对包名排序。(示例有多版本,我们会对示例编号, 这样可以明确当前正在讨论的是哪。)
<u><i>gopl.io/ch1/echo1</i></u>
```go
@@ -30,37 +30,37 @@ func main() {
}
```
註釋語句以`//`開頭。對於程序員來説//之到行末之所有的容都是註釋,被編譯器忽略。按照例,我在每包的包明前添加註釋;對於`main package`註釋包含一句或幾句話,從整體角度程序做描述。
注释语句以`//`开头。对于程序员来说//之到行末之所有的容都是注释,被编译器忽略。按照例,我在每包的包明前添加注释;对于`main package`注释包含一句或几句话,从整体角度程序做描述。
var明定義了兩個string型的量s和sep。變量會在聲明時直接初始化。如果變量沒有顯式初始化,則被隱式地予其型的*零值*zero value數值類型是0字符串型是空字符串""。這個例子里,明把s和sep式地初始化成空字符串。第2章再來詳細地講解變量和明。
var明定义了两个string型的量s和sep。变量会在声明时直接初始化。如果变量没有显式初始化,则被隐式地予其型的*零值*zero value数值类型是0字符串型是空字符串""。这个例子里,明把s和sep式地初始化成空字符串。第2章再来详细地讲解变量和明。
對數值類Go言提供了常規的數值和邏輯運算符。而string型,`+`算符接字符串(譯註和C++或者js是一的)。所以表式:
对数值类Go言提供了常规的数值和逻辑运算符。而string型,`+`算符接字符串(译注和C++或者js是一的)。所以表式:
```go
sep + os.Args[i]
```
表示接字符串sep和os.Args。程序中使用的句:
表示接字符串sep和os.Args。程序中使用的句:
```go
s += sep + os.Args[i]
```
是一條*賦值語句*, s的值跟sepos.Args[i]連接後賦值迴s價於
是一条*赋值语句*, s的值跟sepos.Args[i]连接后赋值回s价于
```go
s = s + sep + os.Args[i]
```
算符`+=`賦值運算符assignment operator種數值運算符或邏輯運算符,如`+``*`,都有對應的賦值運算符。
算符`+=`赋值运算符assignment operator种数值运算符或逻辑运算符,如`+``*`,都有对应的赋值运算符。
echo程序可以每循一次出一個參數,這個版本是不地把新文本追加到末尾來構造字符串。字符串s開始爲空,卽值爲"",每次循環會添加一些文本;第一次迭代之後,還會再插入一空格,因此循環結束時每個參數中間都有一空格。是一二次加工quadratic process當參數數量龐大時,開銷很大,但是對於echo這種情形不大可能出。本章會介紹echo的若榦改進版,下一章解低效問題
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,11 +68,11 @@ for initialization; condition; post {
}
```
for循環三個部分不需括號包圍。大括號強製要求, 左大括號必須和*post*句在同一行。
for循环三个部分不需括号包围。大括号强制要求, 左大括号必须和*post*句在同一行。
*initialization*句是可的,在循環開始前行。*initalization*如果存在,必是一條*簡單語句*simple statement,短變量聲明、自增句、賦值語句或函數調用。`condition`是一個布爾表達boolean expression其值在每次循迭代開始時計算。如果`true`則執行循環體語句。`post`句在循環體執行結束後執行,之再次`conditon`求值。`condition``false`,循環結束。
*initialization*句是可的,在循环开始前行。*initalization*如果存在,必是一条*简单语句*simple statement,短变量声明、自增句、赋值语句或函数调用。`condition`是一个布尔表达boolean expression其值在每次循迭代开始时计算。如果`true`则执行循环体语句。`post`句在循环体执行结束后执行,之再次`conditon`求值。`condition``false`,循环结束。
for循環的這三個部分每都可以省略,如果省略`initialization``post`,分也可以省略:
for循环的这三个部分每都可以省略,如果省略`initialization``post`,分也可以省略:
```go
// a traditional "while" loop
@@ -81,7 +81,7 @@ for condition {
}
```
如果`condition`也省略了,像下面這樣
如果`condition`也省略了,像下面这样
```go
// a traditional infinite loop
@@ -90,9 +90,9 @@ for {
}
```
這就變成一個無限循環,盡管如此,可以用其他方式止循, 如一`break``return`句。
这就变成一个无限循环,尽管如此,可以用其他方式止循, 如一`break``return`句。
`for`的另一形式, 在某種數據類型的區間range上遍,如字符串或切片。`echo`的第二版本展示了這種形式:
`for`的另一形式, 在某种数据类型的区间range上遍,如字符串或切片。`echo`的第二版本展示了这种形式:
<u><i>gopl.io/ch1/echo2</i></u>
```go
@@ -113,11 +113,11 @@ func main() {
}
```
每次循迭代,`range`生一值;索引以及在索引的元素值。這個例子不需要索引,但`range`法要求, 要理元素, 必須處理索引。一思路是把索引賦值給一個臨時變量, 如`temp`, 然忽略它的值但Go言不允使用用的局部local variables爲這會導致編譯錯誤
每次循迭代,`range`生一值;索引以及在索引的元素值。这个例子不需要索引,但`range`法要求, 要理元素, 必须处理索引。一思路是把索引赋值给一个临时变量, 如`temp`, 然忽略它的值但Go言不允使用用的局部local variables为这会导致编译错误
Go言中這種情況的解方法是用`空標識符`blank identifier`_`(也就是下劃線)。空標識符可用任何法需要量名但程序邏輯不需要的候, 例如, 在循里,丟棄不需要的循索引, 保留元素值。大多的Go程序員都會像上面這樣使用`range``_``echo`程序,因爲隱式地而非示地索引os.Args容易寫對
Go言中这种情况的解方法是用`空标识符`blank identifier`_`(也就是下划线)。空标识符可用任何法需要量名但程序逻辑不需要的候, 例如, 在循里,丢弃不需要的循索引, 保留元素值。大多的Go程序员都会像上面这样使用`range``_``echo`程序,因为隐式地而非示地索引os.Args容易写对
`echo`這個版本使用一條短變量聲明來聲明併初始化`s``seps`,也可以將這兩個變量分開聲明,明一個變量有好幾種方式,下面些都等
`echo`这个版本使用一条短变量声明来声明并初始化`s``seps`,也可以将这两个变量分开声明,明一个变量有好几种方式,下面些都等
```go
s := ""
@@ -126,11 +126,11 @@ var s = ""
var s string = ""
```
用哪不用哪種,爲什麽呢?第一形式,是一條短變量聲明,最簡潔,但能用在函數內部,而不能用於包變量。第二形式依賴於字符串的默初始化零值機製,被初始化""。第三形式用得很少,除非同時聲明多個變量。第四形式式地標明變量的型,當變量類型與初值型相同時,類型冗,但如果兩者類型不同,變量類型就必了。實踐中一般使用前兩種形式中的某,初始值重要的話就顯式地指定量的型,否使用式初始化。
用哪不用哪种,为什么呢?第一形式,是一条短变量声明,最简洁,但能用在函数内部,而不能用于包变量。第二形式依赖于字符串的默初始化零值机制,被初始化""。第三形式用得很少,除非同时声明多个变量。第四形式式地标明变量的型,当变量类型与初值型相同时,类型冗,但如果两者类型不同,变量类型就必了。实践中一般使用前两种形式中的某,初始值重要的话就显式地指定量的型,否使用式初始化。
如前文所述,每次循迭代字符串s的容都更新。`+=`接原字符串、空格和下個參數,産生新字符串, 把它賦值給`s``s`來的內容已不再使用,將在適當時機對它進行垃圾收。
如前文所述,每次循迭代字符串s的容都更新。`+=`接原字符串、空格和下个参数,产生新字符串, 把它赋值给`s``s`来的内容已不再使用,将在适当时机对它进行垃圾收。
如果接涉及的數據量很大,這種方式代高昂。一種簡單且高效的解方案是使用`strings`包的`Join`
如果接涉及的数据量很大,这种方式代高昂。一种简单且高效的解方案是使用`strings`包的`Join`
<u><i>gopl.io/ch1/echo3</i></u>
```go
@@ -139,16 +139,16 @@ func main() {
}
```
,如果不關心輸出格式,想看看出值,或許隻是爲了調試,可以用`Println`爲我們格式化出。
,如果不关心输出格式,想看看出值,或许只是为了调试,可以用`Println`为我们格式化出。
```go
fmt.Println(os.Args[1:])
```
這條語句的輸出結果跟`strings.Join`得到的果很像,是被放到了一方括里。切片都被打印成這種格式。
这条语句的输出结果跟`strings.Join`得到的果很像,是被放到了一方括里。切片都被打印成这种格式。
**練習 1.1** `echo`程序,使其能打印`os.Args[0]`卽被執行命令本身的名字。
**练习 1.1** `echo`程序,使其能打印`os.Args[0]`即被执行命令本身的名字。
**練習 1.2** `echo`程序,使其打印每個參數的索引和值,每一行。
**练习 1.2** `echo`程序,使其打印每个参数的索引和值,每一行。
**練習 1.3**實驗測量潛在低效的版本和使用了`strings.Join`的版本的運行時間差異1.6節講解了部分`time`11.4展示了如何寫標準測試程序,以得到繫統性的性能評測。)
**练习 1.3**实验测量潜在低效的版本和使用了`strings.Join`的版本的运行时间差异1.6节讲解了部分`time`11.4展示了如何写标准测试程序,以得到系统性的性能评测。)