我力圖尊重每個人的喜好,因此我通常會避開相關爭論:哪種程式語言、文字編輯器或者作業系統才是最好的。然而,我最近很多次被問到為什麼我喜歡並且大量使用 Go,所以寫下這篇文章 :-)
我的經歷/背景
我已經使用 C 和 Perl 進行了很多規模巨集大的專案。我也用 Python、Ruby、 C++、CHICKEN Scheme、Emacs Lisp、Rust和Java (僅僅針對Android )編寫程式。我瞭解一些 Lua、PHP、Erlang 和 Haskell。我以前使用 Delphi 開發了很多程式。
在 2009 年,當它首次釋出時,我簡要地瞭解了一下 Go。當 Go1.0 在 2012 年釋出時,我認真地開始使用該語言。Go1.0 的一個特色是 Go 1 相容性保證的釋出。我仍然在生產環境中執行著這些程式碼 ,它們是我在2012年編寫的,基本上沒有修改過。
一、清晰性
格式化
按照慣例,Go使用 gofmt 來格式化程式碼。以程式設計方式來格式化程式碼並不是新的想法,但與它的先輩們相比,gofmt 嚴格地支援一種規範風格。
用相同的方式格式化所有程式碼,使得閱讀程式碼更容易,因為程式碼令人感覺似曾相識。這不僅有助於閱讀標準庫或 Go 編譯器,也有助於和許多程式碼庫打交道—想想看開源或者大公司。
此外,在程式碼審查(Code Review)期間,自動格式化能大大節省時間,因為在程式碼能夠被審計前,程式碼的規範風格不再需要人為處理:現在,你能讓持續整合系統驗證 gofmt 並沒有產生差異。
有趣的是,有了編輯器在儲存檔案時應用 gofmt,我寫程式碼的方式也已經改變。我曾經試圖匹配格式化程式執行後的內容,之後再讓gofmt 更正我的錯誤。如今,我儘可能快地表達我的想法,並且相信 gofmt 能夠使得格式化的更好(這個例子是我可能會寫的內容,點選Format)。
高質量的程式碼
所有我已經閱讀的標準庫的質量都是極其高的。其中一個例子就是 image/jpeg 包:我當時並不知道 JPEG 是如何工作的,但通過在閱讀維基百科中有關介紹 JPEG 的文章和閱讀 image/jpeg 原始碼之間切換,我輕易地明白了JPEG是如何工作的。如果包中還有一些註釋,我把它看作教學實施。
觀點
我已經慢慢地認同 Go 社群秉承的很多觀點,比如:
- 變數預設情況下應該簡短,並且能夠從它的宣告中進一步變得更具描述性。
- 保持依賴關係樹短小精悍(以一種合理的程度):有點重複程式碼比一點依賴更好。
- 引入抽象層是有代價的。Go程式碼通常是相當清晰的,但這是有代價的,因為有時候程式碼有點重複。
- 參見程式碼審計說明和Go格言獲取更多資訊。
很少的關鍵字和抽象層
Go 規範僅僅列出了 25 個關鍵字,而我能很容易地記在腦中。
根據我的經驗,少量的抽象層次和概念使得該語言容易學習,並且很快感到適應。
當我們在談論它時:我對 Go 規範的可讀性感到驚訝。它真的看起來是針對程式設計師(而不是標準委員會?)
二、速度
反饋快/延遲低
我喜歡快速的反饋:我喜歡快速載入的網站,我更喜歡流暢、不會滯後的使用者介面,並且任何時候我都將選擇一個快速的工具,而不是一個功能更強大的工具。大型網站效能的調查結果證明這種行為被大量使用者認可。
Go 編譯器的作者滿足了我對低延遲的期望:編譯速度對他們來講很重要,並且新的優化需要仔細地衡量是否會降低編譯速度。
我有一個之前沒有用過 Go 的朋友。在使用 go get 命令安裝了 RobustIRC 橋之後,他得出結論,Go 一定是一種解釋性語言,我不得不糾正他:不,Go 編譯器本來就這麼快。
大部分 Go 工具也不例外,例如 gofmt 或者 goimports 是驚人的快。
最大化利用資源
對於批量應用程式(相對於互動式應用程式),充分利用可用資源通常比低延遲更重要。
配置和更改 Go 程式利用所有可用的 IOPS、網路頻寬和計算能力是很容易的。例如,我之前寫過填充 1Gbps 的鏈路資訊,並且優化 debiman 利用所有可用的資源,這減少了幾小時執行時間。
三、豐富的標準庫
Go 標準庫提供了有效地使用通用通訊協議和資料儲存格式/機制的方法,如TCP/IP、HTTP、JPEG、SQL等。
Go 的標準庫是我迄今看到的最好的標準庫。我認為它組織良好、清晰、精細又全面:我經常發現只需使用標準庫和一兩個外部包就可以編寫出大小合理的程式。
領域特定的資料型別和演算法(通常)不包括在標準庫內,而是包括在第三方庫中,例如 golang.org/x/net/html。在新程式碼合入標準庫之前,golang.org/x名稱空間也充當了新程式碼的暫存區:Go 1 相容性保證排除任何破壞性的改變,即使這些改變看起來很明顯是有價值的。golang.org/x/crypto/ssh就是一個典型的例子,為了建立更安全的預設配置,它不得不打破現有的程式碼。
四、工具
我使用 go get 工具來下載、編譯、安裝和更新 Go 包。
所有我用到的 Go 程式碼庫都用內建的 testing 工具。這不僅令測試容易和快速,而且使得覆蓋率報告很容易生成。
每當一個程式使用比預期更多的資源時,我就使用 pprof。參見 golang.org 釋出的有關 pprof 的博文,或者我釋出的有關優化 Debian 程式碼搜尋的博文。在匯入 net/http/pprof 包之後,你可以在伺服器執行時對其進行配置,而無需重新編譯或重新啟動。
交叉編譯就像設定 GOARCH 環境變數一樣簡單,例如樹莓派3 只需設定 GOARCH=arm64。值得注意的是,工具也能夠跨平臺執行!比如,我能在我的 AMD64 電腦上配置 gokrazy:go tool pprof ~/go/bin/linux_arm64/dhcp http://gokrazy:3112/debug/pprof/heap。
godoc 以純文字形式顯示文件,或者通過 HTTP 提供服務。godoc.org 是一個公共例項,但是我在本地執行了一個例項,這樣我就可以在離線時或者包還未釋出時使用了。
需要注意的是,這些標準工具和 Go 語言是互相伴隨的。如果這些標準工具來自於 C 語言,上述每一項將是一個重大的成就。在 Go 中,我們認為這是理所應當的。
開始學習
希望我已經說清楚了,為什麼我喜歡使用Go。
如果你有興趣開始使用 Go,請核查初學者的資源獲取相關資訊,這也是我們引導剛加入Gophers Slack頻道的人需要核查的。參見https://golang.org/help/。
注意事項
當然,沒有程式設計工具是完全沒有問題的。鑑於這篇文章解釋為什麼 Go 是我最喜歡的程式語言,所以該文只討論了好的一面。不過,我將順便地提及一些問題:
- 如果你使用的 Go 包還沒有提供穩定的 API,你可能想要使用特定的、已知的能夠正常執行的版本。最好的辦法是用 dep 工具,在編寫 Go 語言時,它還不是 Go 的一部分。
- 地道的 Go 程式碼不一定能轉化為最高效能的機器程式碼,而且執行時間需要付出一些(小的)代價。在極少的情況下,我發現有效能缺乏的情況,我成功地訴諸於 cgo 或者彙編器。如果你的範圍是硬實時應用程式或其他效能極其關鍵的程式碼,你的情況就可能不一樣了。
- 我之前寫到 Go 標準庫是我見過的最好的標準庫,但是那不意味著它一點問題都沒有。其中一個例子是 go/ast—標準庫中最古老的包之一,當以程式設計的方式修改 Go 程式碼時,用它處理註釋時會很複雜。