Merge pull request #219 from prife/master

polish up chapter ch1/ch1-01.md
This commit is contained in:
chai2010 2016-01-20 13:18:27 +08:00
commit 043e92312c

View File

@ -1,6 +1,6 @@
## 1.1. Hello, World ## 1.1. Hello, World
我們以1978年出版的C語言聖經[《The C Programming Language》](http://s3-us-west-2.amazonaws.com/belllabs-microsite-dritchie/cbook/index.html)中經典的“hello world”案例來開始吧譯註本書作者之一Brian W. Kernighan也是C語言聖經一書的作者。C語言對Go語言的設計産生了很多影響。用這個例子我們來講解一些Go語言的核心特性 我們以現已成爲傳統的“hello world”案例來開始吧, 這個例子首次出現於1978年出版的C語言聖經[《The C Programming Language》](http://s3-us-west-2.amazonaws.com/belllabs-microsite-dritchie/cbook/index.html)譯註本書作者之一Brian W. Kernighan也是C語言聖經一書的作者。C語言是直接影響Go語言設計的語言之一。這個例子體現了Go語言一些核心理念。
```go ```go
gopl.io/ch1/helloworld gopl.io/ch1/helloworld
@ -13,7 +13,7 @@ func main() {
} }
``` ```
Go是一門編譯型語言Go語言的工具鏈將源代碼和其依賴一起打包,生成機器的本地指令(譯註:靜態編譯)。Go語言提供的工具可以通過go命令下的一繫列子命令來調用。最簡單的一個子命令就是run。這個命令會將一個或多個文件名以.go結尾的源文件和關聯庫鏈接到一起然後運行最終的可執行文件。本書將用$表示命令行的提示符。) Go是一門編譯型語言Go語言的工具鏈將源代碼及其依賴轉換成計算機的機器指令(譯註:靜態編譯)。Go語言提供的工具都通過一個單獨的命令`go`調用,`go`命令有一繫列子命令。最簡單的一個子命令就是run。這個命令編譯一個或多個以.go結尾的源文件鏈接庫文件併運行最終生成的可執行文件。本書使用$表示命令行提示符。)
``` ```
$ go run helloworld.go $ go run helloworld.go
@ -25,53 +25,52 @@ $ go run helloworld.go
Hello, 世界 Hello, 世界
``` ```
Go語言原生支持Unicode標準所以你可以用Go語言處理世界上的任何自然語言 Go語言原生支持Unicode,它可以處理全世界任何語言的文本
如果你希望自己的程序不隻是簡單的一次性實驗那麽你一定會希望能夠編譯這個程序併且能夠將編譯結果保存下來以備將來之用。這個可以用build子命令來實現 如果不隻是一次性實驗你肯定希望能夠編譯這個程序保存編譯結果以備將來之用。可以用build子命令
``` ```
$ go build helloworld.go $ go build helloworld.go
``` ```
這會創建一個名爲helloworld的可執行的二進製文件譯註在Windows繫統下生成的可執行文件是helloworld.exe增加了.exe後綴名之後你可以在任何時間去運行這個二進製文件不需要其它的任何處理(譯註:因爲是靜態編譯,所以也不用擔心在繫統庫更新的時候衝突,幸福感滿滿)。 這個命令生成一個名爲helloworld的可執行的二進製文件譯註在Windows繫統下生成的可執行文件是helloworld.exe增加了.exe後綴名之後你可以隨時運行它不需任何處理譯註因爲是靜態編譯所以也不用擔心在繫統庫更新的時候衝突幸福感滿滿
下面是運行我們的編譯結果樣例譯註在Windows繫統下在命令行直接輸入helloworld.exe命令運行
``` ```
$ ./helloworld $ ./helloworld
Hello, 世界 Hello, 世界
``` ```
譯註在Windows繫統下在命令行直接輸入helloworld.exe命令運行
本書中我們所有的例子都做了一個特殊標記,你可以通過這些標記在 http://gopl.io 在線網站上找到這些樣例代碼,比如這個 本書中, 所有的示例代碼上都有一行標記,利用這些標記, 可以從[gopl.io](http://gopl.io)網站上本書源碼倉庫里獲取代碼:
``` ```
gopl.io/ch1/helloworld gopl.io/ch1/helloworld
``` ```
如果你執行 `go get gopl.io/ch1/helloworld` 命令,go命令能夠自己從網上獲取到這些代碼譯註需要先安裝Git或Hg之類的版本管理工具併將對應的命令添加到PATH環境變量中且將這些代碼放到對應目録中譯註序言已經提及需要先設置好GOPATH環境變量下載的代碼會放在 $GOPATH/src/gopl.io/ch1/helloworld 目録)。更詳細的介紹在2.6和10.7章節中 執行 `go get gopl.io/ch1/helloworld` 命令,就會從網上獲取代碼譯註需要先安裝Git或Hg之類的版本管理工具併將對應的命令添加到PATH環境變量中併放到對應目録中譯註序言已經提及需要先設置好GOPATH環境變量下載的代碼會放在 $GOPATH/src/gopl.io/ch1/helloworld 目録)。2.6和10.7節有這方面更詳細的介紹
我們來討論一下程序本身。Go語言的代碼是通過package來組織的package的概念和你知道的其它語言里的libraries或者modules概念比較類似。一個package會包含一個或多個.go結束的源代碼文件。每一個源文件都是以一個package xxx的聲明語句開頭的比如我們的例子里就是package main。這行聲明語句表示該文件是屬於哪一個package緊跟着是一繫列import的package名表示這個文件中引入的package。再之後是本文件本身的代碼 來討論下程序本身。Go語言的代碼通過**包**package組織包類似於其它語言里的庫libraries或者模塊modules。一個包由位於單個目録下的一個或多個.go源代碼文件組成, 目録定義包的作用。每個源文件都以一條`package`聲明語句開始,這個例子里就是`package main`, 表示該文件屬於哪個包緊跟着一繫列導入import的包之後是存儲在這個文件里的程序語句
Go的標準庫已經提供了100多個package用來完成一門程序語言的一些常見的基本任務比如輸入、輸出、排序或者字符串/文本處理。比如fmt這個package就包括接收輸入、格式化輸出的各種函數。Println是其中的一個常用的函數可以用這個函數來打印一個或多個值該函數會將這些參數用空格隔開進行輸出併在輸出完畢之後在行末加上一個換行符 Go的標準庫提供了100多個包以支持常見功能如輸入、輸出、排序以及文本處理。比如`fmt`包,就含有格式化輸出、接收輸入的函數。`Println`是其中一個基礎函數,可以打印以空格間隔的一個或多個值,併在最後添加一個換行符,從而輸出一整行
package main是一個比較特殊的package。這個package里會定義一個獨立的程序這個程序是可以運行的而不是像其它package一樣對應一個library。在main這個package里main函數也是一個特殊的函數這是我們整個程序的入口譯註其實C繫語言差不多都是這樣。main函數所做的事情就是我們程序做的事情。當然了main函數一般是通過是調用其它packge里的函數來完成自己的工作比如fmt.Println `main`包比較特殊。它定義了一個獨立可執行的程序,而不是一個庫。在`main`里的`main` *函數* 也很特殊它是整個程序執行時的入口譯註其實C繫語言差不多都是這樣。`main`函數所做的事情就是程序做的。當然了,`main`函數一般調用其它包里的函數完成很多工作, 比如`fmt.Println`
我們必須告訴編譯器如何要正確地執行這個源文件需要用到哪些package這就是import在這個文件里扮演的角色。上述的hello world例子隻用到了一個其它的package就是fmt。一般情況下需要import的package可能不隻一個 必須告訴編譯器源文件需要哪些包,這就是`import`聲明以及隨後的`package`聲明扮演的角色。hello world例子隻用到了一個包大多數程序需要導入多個包
這也正是因爲go語言必須引入所有要用到的package的原則假如你沒有在代碼里import需要用到的package程序將無法編譯通過同時當你import了沒有用到的package也會無法編譯通過譯註Go語言編譯過程沒有警告信息爭議特性之一 必須恰當導入需要的包,缺少了必要的包或者導入了不需要的包,程序都無法編譯通過。這項嚴格要求避免了程序開發過程中引入未使用的包。譯註Go語言編譯過程沒有警告信息爭議特性之一
import聲明必須跟在文件的package聲明之後。在import語句之後則是各種方法、變量、常量、類型的聲明語句(分别用關鍵字func, var, const, type來進行定義)。這些內容的聲明順序併沒有什麽規定,可以隨便調整順序(譯註:最好還是定一下規范)。我們例子里的程序比較簡單隻包含了一個函數。併且在該函數里也隻調用了一個其它函數。爲了節省空間有些時候的例子我們會省略package和import聲明但是讀者需要註意這些聲明是一定要包含在源文件里的 `import`聲明必須跟在文件的`package`聲明之後。隨後,則是組成程序的函數、變量、常量、類型的聲明語句(分别由關鍵字`func`, `var`, `const`, `type`定義)。這些內容的聲明順序併不重要。(譯註:最好還是定一下規范)。這個例子的程序已經盡可能短了,隻聲明了一個函數, 其中隻調用了一個其他函數。爲了節省篇幅,有些時候, 示例程序會省略`package`和`import`聲明,但是,這些聲明在源代碼里有,併且必須得有才能編譯
一個函數的聲明包含func這個關鍵字、函數名、參數列表、返迴結果列表我們例子里的main函數參數列表和返迴值都是空的)以及包含在大括號里的函數體。關於函數的更詳細描述在第五章。 一個函數的聲明由`func`關鍵字、函數名、參數列表、返迴值列表(這個例子里的`main`函數參數列表和返迴值都是空的)以及包含在大括號里的函數體組成。第五章進一步考察函數
Go語言是一門不需要分號作爲語句或者聲明結束的語言,除非要在一行中將多個語句、聲明隔開。然而在編譯時,編譯器會主動在一些特定的符號譯註比如行末是一個標識符、一個整數、浮點數、虛數、字符或字符串文字、關鍵字break、continue、fallthrough或return中的一個、運算符和分隔符++、--、)、]或}中的一個) 後添加分號所以在哪里加分號合適是取決於Go語言代碼的。例如在Go語言中的函數聲明和 { 大括號必須在同一行而在x + y這樣的表達式中在+號後換行可以,但是在+號前換行則會有問題(譯註:以+結尾的話不會被插入分號分隔符但是以x結尾的話則會被分號分隔符從而導致編譯錯誤 Go語言不需要在語句或者聲明的末尾添加分號,除非一行上有多條語句。實際上,編譯器會主動把特定符號後的換行符轉換爲分號, 因此換行符添加的位置會影響Go代碼的正確解析。譯註比如行末是一個標識符、一個整數、浮點數、虛數、字符或字符串文字、關鍵字break、continue、fallthrough或return中的一個、運算符和分隔符++、--、)、]或}中的一個)。舉個例子, 函數的左括號`{`必須和`func`函數聲明在同一行上, 且位於末尾,不能獨占一行,而在表達式`x + y`中,可在`+`後換行,不能在`+`前換行(譯註:以+結尾的話不會被插入分號分隔符但是以x結尾的話則會被分號分隔符從而導致編譯錯誤
Go語言在代碼格式上采取了很強硬的態度。gofmt工具會將你的代碼格式化爲標準格式譯註這個格式化工具沒有任何可以調整代碼格式的參數Go語言就是這麽任性併且go工具中的fmt子命令會自動對特定package下的所有.go源文件應用gofmt工具格式化。如果不指定package則默認對當前目録下的源文件進行格式化。本書中的所有代碼已經是執行過gofmt後的標準格式代碼。你應該在自己的代碼上也執行這種格式化。規定一種標準的代碼格式可以規避掉無盡的無意義的撕逼譯註也導致了Go語言的TIOBE排名較低因爲缺少撕逼的話題。當然了這可以避免由於代碼格式導致的邏輯上的歧義 Go語言在代碼格式上采取了很強硬的態度。`gofmt`工具把代碼格式化爲標準格式譯註這個格式化工具沒有任何可以調整代碼格式的參數Go語言就是這麽任性併且`go`工具中的`fmt`子命令會對指定包, 否則默認爲當前目録, 中所有.go源文件應用`gofmt`命令。本書中的所有代碼都被gofmt過。你也應該養成格式化自己的代碼的習慣。以法令方式規定標準的代碼格式可以避免無盡的無意義的瑣碎爭執譯註也導致了Go語言的TIOBE排名較低因爲缺少撕逼的話題。更重要的是這樣可以做多種自動源碼轉換如果放任Go語言代碼格式這些轉換就不大可能了
很多文本編輯器都可以設置爲保存文件時自動執行gofmt所以你的源代碼應該總是會被格式化。這里還有一個相關的工具goimports會自動地添加你代碼里需要用到的import聲明以及需要移除的import聲明。這個工具併沒有包含在標準的分發包中然而你可以自行安裝: 很多文本編輯器都可以配置爲保存文件時自動執行`gofmt`,這樣你的源代碼總會被恰當地格式化。還有個相關的工具,`goimports`,可以根據代碼需要, 自動地添加或刪除`import`聲明。這個工具併沒有包含在標準的分發包中,可以用下面的命令安裝:
``` ```
$ go get golang.org/x/tools/cmd/goimports $ go get golang.org/x/tools/cmd/goimports
``` ```
對於大多數用戶來説,下載、build package、運行測試用例、顯示Go語言的文檔等等常用功能都是可以用go的工具來實現的。這些工具的詳細介紹我們會在10.7節中提到 對於大多數用戶來説,下載、編譯包、運行測試用例、察看Go語言的文檔等等常用功能都可以用go的工具完成。10.7節詳細介紹這些知識