前言
Golang自2009年釋出第一個版本,2012年釋出1.0版本。在這10年的時間裡,不斷有開發者加入Golang的陣營中,不斷共建Golang生態。其中比較有代表性的Golang編寫軟體作品是Docker和Kubernetes。從目前Golang的發展時間和社群活躍度來看,Golang無疑是一門成功的程式語言。
大道至簡
有次微信公開課中,微信之父張小龍提到微信成功的祕訣就是簡單,把所有功能做到最簡單,UI最簡單,使用者使用最簡單。這樣使得競品無法抄襲,因為微信是最簡單的,對手加了一點東西都是冗餘。那麼什麼使得Golang這麼成功呢?
你可能會提到下面的原因:
- 編譯速度快
- 執行速度快
- 部署無依賴
- 工具齊全
- 官方庫和第三方開源庫豐富
但是這些不是語言特性,全都非常重要但是不是真正的答案。比較少談起的是:介面或者併發這樣真正的語言特性。真正的原因是簡單。Golang是簡單的,至少相比於當前的程式語言來說是簡單的。簡單有很多面,簡單同時也是複雜的。語言使用上的簡單對應的肯定是底層實現原理的複雜,和設計人員的精美設計的結果。
其他程式語言
Java,JavaScript,C#,C++,PHP,Python 這些程式語言積極的互相借鑑語言特性,例如這些語言都會有class(類)。它們正在彙總為一個簡單的大型語言
程式語言需要不同的維度考慮:
邏輯程式設計(logic programming)
過程程式設計(procedural programming)
函式程式設計(functional programming)
物件導向程式設計(object-oriened programming)
併發程式設計(concurrent programming)
如果所有的程式語言都彙總在一起,那麼我們思考的程式設計模式就會是一樣的。但是有不同的思考方式是好的,需要不同的程式語言解決不同的問題。我們要的不是僅僅只有一個工具,而是一堆工具,不同的工具聚焦解決不同的問題。前面提到的語言,如Java8,C++14正在討論新的特性,這些語言通過加入特性在不斷的競爭。當某個語言出現了某個特性時,另外的語言一定會跟隨,例如C++11/14加入的型別推導,不由得讓人想起了指令碼語言Python。這些語言在發展的過程會變得越來越複雜,同時也會變得越來越相似。它們會膨脹得沒有區分度。
Golang
Golang沒有嘗試像其他程式語言,不在特性上競爭。Golang 1.0版本釋出時,這門語言的特性就已經固定了。很多Golang的新手會要求Golang具有一些他們知道的其他程式語言的特性。但是這些特性不屬於Golang,這門程式語言的特性已經固定了。加入新特性不會使Golang變得更好,只會使它變得更大,更臃腫。
可讀性
如果一門程式語言有太多特性,你會浪費時間在挑選用哪個的問題上。然後實現,精簡,可能會回想和重做。
實際工作中,經常會發生的一幕是,有人會問,“為什麼這些程式碼要這樣寫,這段程式碼是怎麼工作的”,這個人可能是其他人,更有可能是你自己。這些程式碼是很難簡單的能理解到,因為它用了一個更加複雜的程式語言,由於複雜程式語言的諸多特性,可能會導致很多分支的結果,所以我們需要分析這段程式碼的各種可能性,一不小心就會掉到坑裡面。所以對於程式設計師來說,更傾向於只有一種實現方法,或者至少應該是儘量少的實現方法,更簡單的實現方法。更多的特性會增加程式語言的複雜度,我們想要簡單的程式語言。更多的特性會讓可讀性受損,我們想要可讀性。可讀性是最重要的。因為可讀性意味著可靠性,如果你能夠讀懂程式碼和它意味著什麼,就會很容易明白它的工作原理。如果它出現問題也會更容易修復。
設計理念
簡單的互動方式是簡單的特性。簡單是Golang的目標。
Golang實際上實現原理非常複雜,但是它看起來很簡單,使用很簡單。語法非常簡單和準確,沒有歧義,沒有驚喜。這需要Golang的創始人/團隊經過大量的設計、實現和優化。所以簡單是掩蓋複雜的一門藝術。
下面會介紹Golang的幾個簡單特性:Gc機制(垃圾回收),goroutine,interface(介面),package(包)。每個簡單的特性後面都是複雜的實現。
垃圾回收
垃圾回收可能是最好的用簡單掩蓋複雜的特性。實現起來非常難,但是很值得。因為有gc機制我們Golang程式碼編寫得更簡單。寫程式碼的時候不需要關心“擁有者”。
併發
Golang原生就支援了併發,而不是依賴第三方庫。Golang併發包括下面三個元素:goroutines(執行體),channels(通訊),select(協調)。
這裡我們只需要暫時先關注goroutine,通過go function(args)啟動一個獨立執行的goroutine。三個字元’g’ ‘o’ ‘ ’就能啟動一個goroutine。很難做到比這更簡單的了。和gc機制一樣,將程式設計人員需要關心的東西最小化。棧的大小,返回值和完成狀態,執行緒 ID等都不用關心。雖然goroutine的實現很複雜,依賴於gc機制和棧管理,但是程式設計人員不用關心這些,只需要go就能啟動一個goroutine。
介面
介面僅僅是方法的集合,沒有資料。很簡單的想法。
type Reader interface { Read([]byte)(int, error) } var r Reader = os.Stdin //靜態檢查 var x interface{} = os.Stdin //靜態檢查 r = x.(Reader) //動態檢查,一定要是精準斷言,否則會panic
在靜態型別語言中加入動態型別轉換,這些需要小心精準的設計。介面的賦值在執行時完成。最好是用“comma, ok”的語法,否則失敗會panic。介面是Golang最有區分度和最強大的特性。深度影響了包的設計。另外包允許組合,例如可以將io.Reader和io.Writer組合為io.ReadWriter。感覺很簡單,實則底層原理很複雜。
包
一個結構化程式和庫的設計。
package big
…
import “math/big”
包的設計花費了Golang團隊大量時間去設計。允許組合,可擴充套件,共享,資料隱藏(大小寫),還有隔離 …。包的設計涉及到程式的設計,語法,命令,編譯,連結,測試等等。但是對於Golang程式設計人員來說只需要使用package定義包,用import引用包即可。這也是用簡單掩蓋複雜的一個例子。
上述的示例都是為了說明Golang使用是非常簡單,實現非常複雜。作為Golang的使用者,我們只需要清楚它的使用即可,而無需關心Golang的複雜實現,這也是Golang團隊的目標。
下面是一個簡單的Golang程式:
package main import ( "fmt" "log" "net/http" ) func 你好_Gophers(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "你好 Gophers!\n") } func main() { http.HandleFunc("/", 你好_Gophers) err := http.ListenAndServe("localhost:12345", nil) if err != nil { log.Fatal("ListenAndServer:", err) } }
掩蓋了下面的複雜過程:
Unicode和UTF8處理
包的引用和使用
Fprintf直接對接網路連線
函式作為引數傳遞(HandleFunc)
真正的併發 —server並沒有阻塞
總結
Golang是使用簡單,底層實現原理複雜的一門程式語言。
參考
https://www.youtube.com/watch?v=cQ7STILAS0M