gopl-zh.github.com/ch1/ch1-01.md

89 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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