'我不喜歡Go語言的十個理由'

"
"
我不喜歡Go語言的十個理由

出處 | AI前線

Go 語言有多火爆?國外如 Google、AWS、Cloudflare、CoreOS 等,國內如七牛、阿里、知乎等都已經開始大規模使用 Go 語言開發相關產品,可以說它是近來風頭最盛的編程語言之一。但再好的編程語言也不會是完美的編程語言,本文作者 Lawrence 使用了三年 Go 語言,並在這三年間參與了幾個大型 Go 語言項目,但三年後他徹底放棄 Go 語言,而且不打算在新項目中使用它。Go 語言帶給他的總體印象是:“好的方面非常好,不好的方面實在令人無法忍受”。Lawrence 在一篇博客文章中列出了他不再喜歡 Go 語言的十大理由,這篇文章很快在 HackerNews 上引發熱議,下面就讓我們一起來看看這十個理由到底有哪些。

不喜歡 Go 語言的十個理由

1. Go 語言使用首字母大小寫來決定標識符的可見性。

以小寫字母開頭的標識符在包內可見,以大寫字母開頭的標識符是公開的。這樣做可能是為了省掉 public 和 private 關鍵字,但是,首字母大寫已經被用來表示其他意思——比如類名的首字母是大寫的,常量完全是大寫的。對於我來說,使用完全小寫的字母來定義全局常量實在是有點不適應。

如果你要定義私有結構體,情況會變得更加糟糕,因為你必須使用小寫字母。例如,你可能有一個結構體叫作 user,那麼你會怎麼定義這個結構體的變量呢?你可能會把它叫作 user,這樣看起來是不是有點奇怪?因為變量的名字跟結構體的名字是一樣的,而且如果編譯器也搞不清楚哪個是哪個,就會拋出編譯錯誤。

type user struct {
name string
}
func main() {
var user *user
user = &user{} // Compile error
}

Go 語言通常會使用比較短的命名方式,比如 u。但是,35 年前,當我還在使用古董機 TRS-80 Basic 的時候就已經不再使用這種單字母的命名方式了。

當然,也有一些與實際開發相關的考慮。比如經常會出現這樣的情況:剛開始定義了一個私有字段或結構體,後來需要把它們變成公開的,這樣就不得不把所有使用這些標識符的地方都修改一遍。即使你不需要把它們變成公開的,但如果要使用 json 包來序列化它們,也不得不這麼做。我就曾經定義過一個包含 74 個私有字段的結構體,因為要使用 json 序列化,不得不把所有字段都變成公開的,並且修改了所有使用這些字段的地方。

通過首字母大寫的方式來決定可見性有一定的侷限性(要麼包內可見,要麼公開)。例如,我經常需要使用文件內部可見的私有標識符,但目前 Go 語言不太可能引入這樣的東西。

2. 在 Go 語言裡,結構體不會顯式聲明它實現了哪些接口,而是通過匹配方法簽名來辨別。

這種設計犯了一個根本性的錯誤:它假設兩個方法如果有相同的簽名就表示有相同的契約。在 Java 中,如果一個類實現了一個接口,它會告訴編譯器它實現了接口的所有方法。如果一個方法返回布爾類型,接口的註釋會寫清楚它的值代表什麼意思(比如,true 表示成功,false 表示失敗)。

但是,Go 語言的結構體可能一方面實現了同樣的接口,但返回值的意思卻是相反的。具體怎麼實現可以自由發揮,因為並沒有接口聲明約束。當然,在 Java 裡也可以這麼做,但這很顯然就是一個 bug。而在 Go 語言中,一個程序員可能在沒有驗證方法兼容性的情況下將一個對象轉成某個接口,這樣很容易引入潛在的 bug。驗證兼容性的負擔不應該強加給 API 使用者,應該由結構體的實現者承擔,並在代碼中聲明清楚。

3. Go 語言中沒有異常,而是通過多個返回值來返回錯誤。

開發者會容易忘了檢查返回值裡是不是包含了錯誤。

db.Exec("DELTE FROM item WHERE id = 2")

在這個語句裡,DELETE 拼寫錯誤,但沒有任何消息告訴你出了什麼問題。如果這個語句是一個大型事務的一部分,那麼整個事務就什麼事都不會做。通過返回值表示錯誤不是個問題,但程序員必須去檢查返回值,或者把它賦值給 _。

另外,看一下這個語句:

user, err := getUserById(userId)

它並不保證 user 或 err 會包含正確的值。user 有可能沒有被賦值(於是讀取這個變量就會出現警告),而如果使用了聯合類型,編譯器只保證正確的那個可以被訪問。

4. Go 語言裡有很多“神奇”的行為。

例如,如果我把源碼文件命名為 i_love_linux.go,在 Mac 上就編譯不過去。而如果我湊巧把一個函數名定義成 init(),在運行時它會自動被調用。這些都是“約定俗成而非配置(convention over configuration)”的表現。對於小型項目來說,這些都無關鍵要,但在大型項目中,它們會給你帶來大麻煩。

5. 因為 Go 語言的首字母大寫約定,很容易出現很多相同的標識符。

比如,一些包名、結構體名和變量名都叫作 item。在 Java 中,包名使用了全限定名,類名首字母是大寫的。有時候,我覺得 Go 代碼不好閱讀,因為可能無法一下子看出一個標識符的作用域是怎樣的。

6. 要進行 Go 代碼自動生成並不容易。

編譯器太過敏感,一些未被使用的導入和變量也會導致構建失敗。在生成大型文件時,它在一開始可能並不知道需要導入那些包,而且可能會出現包名衝突,這種衝突也不好處理,因為即使你知道包名,卻不知道導入的符號來自哪裡。即使你知道,生成的代碼為了避免衝突也會強制使用別名。在 Java 中,這些問題可以通過使用全限定類名來解決,而在 Go 語言中是不能這樣做的。

7. Go 語言沒有三元運算符(?:)。

C 語言風格的編程語言都提供了這個運算符。在使用 Go 語言時,我無時不刻都在想念著這個運算符。當每個人都覺得這個運算符很有用的時候,Go 語言卻把它移除掉了。原來很優雅的語句,比如:

var serializeType = showArchived ? model.SerializeAll : model.SerializeNonArchivedOnly

不得不寫成這樣:

var serializeType model.SerializeType
if showArchived {
serializeType = model.SerializeAll
} else {
serializeType = model.SerializeNonArchivedOnly
}

8. sort 接口很笨。

如果你有 10 個不同的結構體需要排序,必須寫 30 個函數,其中有 20 個是幾乎一樣的。而且代碼寫起來很麻煩,你或許可以把它們委託給另一個 Less(),但你必須保證 Len() 和 Swap() 是兼容的。而且這樣的代碼看起來很奇怪,轉型看起來像是在調用函數:

sort.Sort(sort.Reverse(UsersByLastSignedInAt(users)))

9. 缺少泛型。

我真的不想使用一門無法實現 Stack 泛型類的語言。臨時的解決方案是使用 append() 函數替代,但現在都什麼年代了,我可不想寫像下面這樣的代碼:

stack = append(stack, object)
object = stack[len(stack) - 1]
stack = stack[:len(stack) - 1]

我很好奇究竟有多少第三方庫使用了 interface{}。可見 Go 語言的類型系統設計得非常糟糕。

10. 這是個小問題,但足以說明 Go 語言設計者沒有完全站在程序員的角度考慮問題。

append() 函數用於擴展一個數組,然後返回新數組:

users = append(users, newUser)

但下面這行代碼總是能夠調用成功:

append(users, newUser)

append() 函數在可能的情況下進行原地數組修改,如果沒有足夠的空間就返回一個新的數組。這樣的 API 設計真是再糟糕不過了。有多少 bug 是因為忘記把結果賦值給變量引起的?有很多。因為即使是在測試時也不一定會觸發數組調整大小(這裡需要說明一下,後來他們修改了編譯器,如果 append() 函數沒有被賦值給變量,就拋出錯誤)。

總 結

這是我個人對使用 Go 語言的一些建議:如果你的程序很小,基本上可以說清楚要實現什麼功能,並且不會與太多外部數據(數據庫、Web 等)打交道,那麼使用 Go 語言是沒有問題的。如果程序很大,有很複雜的數據結構,或者需要處理大量的外部數據,那麼 Go 語言的類型系統會讓你抓狂,你最好選擇其他靜態類型的語言(類型系統比較完善)或者動態語言(不會礙手礙腳)。

網友熱議

雖然這篇文章並非最近剛剛發佈,但它這一次登上 HackerNews 後依然引發了網友的熱烈討論,收穫了數百個討論並在很短的時間裡再次登上 HackerNews 熱度榜。有的網友對作者的觀點表示認同,並表示雖然會將 Go 語言作為一種備用的編程語言,但如無必要不會再去用它。有的網友則覺得作者提出的大部分缺點都不是問題,並希望 Go 語言保持初心,不要隨意修改。以下是我們整理的網友精彩評論。

網友lostingthefight:

我從 2015 年開始就在生產環境中使用 Go 語言。說實話,除了三元運算符,其他的對我來說都不是問題。我主要從事 REST API 方面的開發,所以面對的場景可能不太一樣。首字母大寫和接口實現問題對我來說也不是個事。Go 語言提供的一些特性在我所使用過的語言中是最好的。再配合一個好的編輯器,就不會錯過任何異常。不過不管怎樣,Go 語言並不完美。有時候 Go 例程很難追蹤,而且對於大型項目來說,模塊過度是個麻煩事。不過,如果有得選擇,我還是不會回到 Java、C#、PHP 或者 NodeJS。

網友kstenerud:

即使是在中型項目中,我也受到了這些問題的困擾。未使用的導入和變量會導致編譯錯誤,這點實在很令人厭煩,所以不得不給編譯器打個補丁(https://github.com/kstenerud/go),把它們變成警告,而不是錯誤。

網友cr0sh:

離最後一次使用 Go 語言已經很長一段時間了。我還記得當初學習 Go 語言的經歷。我和我的同事被安排為我們的僱主(一家雲服務提供商)開發一個接口,允許 Rancher(或者 Rancher 的客戶端,具體忘了是哪個了)使用我們的後端系統(使用 PHP、Java 和 Bash 開發的)來分配服務器。Rancher 是使用 Go 語言開發的,但我們都沒接觸過 Go 語言,我們都是 PHP 開發者,於是我們開始學習 Go 語言。我們大概花了一個禮拜時間學習 Go 語言,一個月之後,我們就開發出了一個可運行的庫,還帶有文檔和測試代碼。但是整個開發過程與文章中所寫的差不多(這裡略去若干罵人的話)……我們已經習慣了在 PHP 中放一些臨時用的代碼,比如為了試驗、調試等原因。但是,Go 語言不允許我們這麼做。要想編譯通過,必須清理掉這些東西,這讓我們感到很抓狂,而且日復一日,一週又一週,然後:我們釋然了。我們可以理解為什麼 Go 語言的設計者要這樣設計,我們甚至希望 PHP 也這麼做。我們後來沒有再隨意亂放臨時代碼,因為這些代碼在後面有可能會給我們帶來麻煩。Go 語言的這種設計確實給開發添加了難度,但另一方面卻可以幫我們避免出現更多的錯誤,或者在未來出現更多的 bug,並讓代碼變得更容易維護。但不管怎樣,我不用 Go 語言已經有好幾年時間了,我不再需要它了。但如果有必要,我還是會用它。或許,這幾年 Go 語言發生了很多變化,不過也有可能變化並不大。無論如何,我從那次經歷中學到了一個道理:在得到你想要的東西之前,必須經歷痛苦和掙扎。我體驗了一門非常獨特的語言,我也因此變成一個更好的開發者。

網友sdegutis:

客觀來說,首字母大寫是個問題,特別是在改變了可見性之後需要重構代碼。不過,使用一個好的 IDE 可以減輕這方面的工作量。更重要的問題是 Go 語言設計者似乎無法體會慣例的重要性。我過去十年所使用的編程語言都鼓勵開發者使用變量、類名和常量慣例。這讓我想起了那些想要讓人們使用 CE(公元)和 BCE(公元前)代替 AD(公元另一種說法)和 BC(公元前另一種說法)的人,他們忽略了後者的習慣性和相關性,就好像他們生活在真空中。我不知道該怎麼說,但這是我不喜歡 Go 語言最主要的原因。有人說 Go 語言是一門借鑑了 C 語言特點的新語言。但我覺得這種說法有點誇張,就好像是說:“現在是 1970 年,C 語言不存在,後面 49 年的事情都還沒有發生”。

網友dawkins:

我從 2012 年就開始在生產環境中使用 Go 語言,我覺得它是一門非常棒的語言。除了文中提到的第八點之外,其他對我來說都不是問題。Go 語言設計者把這門語言設計成這樣,我是感到滿意的,但讓我感到困擾的是最近做出的一些變更:模塊和 Go 2 提案。我希望他們能夠保持最初的願景不變。

網友lkramer:

文章提到的問題似乎都很合理,但它們都不足以讓我討厭這門語言。或許首字母大寫也是困擾我的一個問題,或許設計者當初可能考慮到可以通過 IDE 來減輕重構工作。但不管怎樣,要把一些東西從私有變成非私有要修改很多文件可能不是一個好的設計。我在錯誤處理方面也吃過幾次苦頭。我不太喜歡異常,但這個問題可以通過顯式忽略變量來解決。Go 語言並不完美,但從我的經驗來看,沒有什麼比 Go 語言更適合用來開發微服務了。

網友diamondo25:

文章提到的問題都不算是問題。我希望 Go 語言可以這樣一路走下去,不要走回老路或者像 Scala 過去幾年所做的那樣……

網友gerbilly:

我只想說一句話:是否選擇一門語言,不要看它的設計,要看它是否可以解決你的問題。

網友dbt00:

Go 語言確實不完美,但我覺得在解決同樣的問題時,它比 Java 或 C++ 更高效。對於文中提到的第二點,我並不喜歡作者舉的例子。我覺得不管在任何一門語言中都不應該定義這種容易產生混淆的接口。所以,這一點對我來說也不是問題。對於第三點,我自己開發了一個小插件,用來檢查錯誤。如果你要對一個片段進行排序,sort.Slice 比 sort.Interface 更好。泛型已經被確認是個問題,解決方案正在路上……

你現在正在使用 Go 語言嗎?你是否喜歡 Go 語言?你認為作者提出的這 10 個理由是 Go 語言的缺點嗎?Go 語言有沒有什麼問題正在困擾著你?歡迎在評論區留下你的觀點和故事。

英文原文:

https://www.teamten.com/lawrence/writings/why-i-dont-like-go.html

HackerNews 網站討論:

https://news.ycombinator.com/item?id=20166806

Go 語言相關文章回顧:

《再見,Python!你好,Go 語言》

"
我不喜歡Go語言的十個理由

出處 | AI前線

Go 語言有多火爆?國外如 Google、AWS、Cloudflare、CoreOS 等,國內如七牛、阿里、知乎等都已經開始大規模使用 Go 語言開發相關產品,可以說它是近來風頭最盛的編程語言之一。但再好的編程語言也不會是完美的編程語言,本文作者 Lawrence 使用了三年 Go 語言,並在這三年間參與了幾個大型 Go 語言項目,但三年後他徹底放棄 Go 語言,而且不打算在新項目中使用它。Go 語言帶給他的總體印象是:“好的方面非常好,不好的方面實在令人無法忍受”。Lawrence 在一篇博客文章中列出了他不再喜歡 Go 語言的十大理由,這篇文章很快在 HackerNews 上引發熱議,下面就讓我們一起來看看這十個理由到底有哪些。

不喜歡 Go 語言的十個理由

1. Go 語言使用首字母大小寫來決定標識符的可見性。

以小寫字母開頭的標識符在包內可見,以大寫字母開頭的標識符是公開的。這樣做可能是為了省掉 public 和 private 關鍵字,但是,首字母大寫已經被用來表示其他意思——比如類名的首字母是大寫的,常量完全是大寫的。對於我來說,使用完全小寫的字母來定義全局常量實在是有點不適應。

如果你要定義私有結構體,情況會變得更加糟糕,因為你必須使用小寫字母。例如,你可能有一個結構體叫作 user,那麼你會怎麼定義這個結構體的變量呢?你可能會把它叫作 user,這樣看起來是不是有點奇怪?因為變量的名字跟結構體的名字是一樣的,而且如果編譯器也搞不清楚哪個是哪個,就會拋出編譯錯誤。

type user struct {
name string
}
func main() {
var user *user
user = &user{} // Compile error
}

Go 語言通常會使用比較短的命名方式,比如 u。但是,35 年前,當我還在使用古董機 TRS-80 Basic 的時候就已經不再使用這種單字母的命名方式了。

當然,也有一些與實際開發相關的考慮。比如經常會出現這樣的情況:剛開始定義了一個私有字段或結構體,後來需要把它們變成公開的,這樣就不得不把所有使用這些標識符的地方都修改一遍。即使你不需要把它們變成公開的,但如果要使用 json 包來序列化它們,也不得不這麼做。我就曾經定義過一個包含 74 個私有字段的結構體,因為要使用 json 序列化,不得不把所有字段都變成公開的,並且修改了所有使用這些字段的地方。

通過首字母大寫的方式來決定可見性有一定的侷限性(要麼包內可見,要麼公開)。例如,我經常需要使用文件內部可見的私有標識符,但目前 Go 語言不太可能引入這樣的東西。

2. 在 Go 語言裡,結構體不會顯式聲明它實現了哪些接口,而是通過匹配方法簽名來辨別。

這種設計犯了一個根本性的錯誤:它假設兩個方法如果有相同的簽名就表示有相同的契約。在 Java 中,如果一個類實現了一個接口,它會告訴編譯器它實現了接口的所有方法。如果一個方法返回布爾類型,接口的註釋會寫清楚它的值代表什麼意思(比如,true 表示成功,false 表示失敗)。

但是,Go 語言的結構體可能一方面實現了同樣的接口,但返回值的意思卻是相反的。具體怎麼實現可以自由發揮,因為並沒有接口聲明約束。當然,在 Java 裡也可以這麼做,但這很顯然就是一個 bug。而在 Go 語言中,一個程序員可能在沒有驗證方法兼容性的情況下將一個對象轉成某個接口,這樣很容易引入潛在的 bug。驗證兼容性的負擔不應該強加給 API 使用者,應該由結構體的實現者承擔,並在代碼中聲明清楚。

3. Go 語言中沒有異常,而是通過多個返回值來返回錯誤。

開發者會容易忘了檢查返回值裡是不是包含了錯誤。

db.Exec("DELTE FROM item WHERE id = 2")

在這個語句裡,DELETE 拼寫錯誤,但沒有任何消息告訴你出了什麼問題。如果這個語句是一個大型事務的一部分,那麼整個事務就什麼事都不會做。通過返回值表示錯誤不是個問題,但程序員必須去檢查返回值,或者把它賦值給 _。

另外,看一下這個語句:

user, err := getUserById(userId)

它並不保證 user 或 err 會包含正確的值。user 有可能沒有被賦值(於是讀取這個變量就會出現警告),而如果使用了聯合類型,編譯器只保證正確的那個可以被訪問。

4. Go 語言裡有很多“神奇”的行為。

例如,如果我把源碼文件命名為 i_love_linux.go,在 Mac 上就編譯不過去。而如果我湊巧把一個函數名定義成 init(),在運行時它會自動被調用。這些都是“約定俗成而非配置(convention over configuration)”的表現。對於小型項目來說,這些都無關鍵要,但在大型項目中,它們會給你帶來大麻煩。

5. 因為 Go 語言的首字母大寫約定,很容易出現很多相同的標識符。

比如,一些包名、結構體名和變量名都叫作 item。在 Java 中,包名使用了全限定名,類名首字母是大寫的。有時候,我覺得 Go 代碼不好閱讀,因為可能無法一下子看出一個標識符的作用域是怎樣的。

6. 要進行 Go 代碼自動生成並不容易。

編譯器太過敏感,一些未被使用的導入和變量也會導致構建失敗。在生成大型文件時,它在一開始可能並不知道需要導入那些包,而且可能會出現包名衝突,這種衝突也不好處理,因為即使你知道包名,卻不知道導入的符號來自哪裡。即使你知道,生成的代碼為了避免衝突也會強制使用別名。在 Java 中,這些問題可以通過使用全限定類名來解決,而在 Go 語言中是不能這樣做的。

7. Go 語言沒有三元運算符(?:)。

C 語言風格的編程語言都提供了這個運算符。在使用 Go 語言時,我無時不刻都在想念著這個運算符。當每個人都覺得這個運算符很有用的時候,Go 語言卻把它移除掉了。原來很優雅的語句,比如:

var serializeType = showArchived ? model.SerializeAll : model.SerializeNonArchivedOnly

不得不寫成這樣:

var serializeType model.SerializeType
if showArchived {
serializeType = model.SerializeAll
} else {
serializeType = model.SerializeNonArchivedOnly
}

8. sort 接口很笨。

如果你有 10 個不同的結構體需要排序,必須寫 30 個函數,其中有 20 個是幾乎一樣的。而且代碼寫起來很麻煩,你或許可以把它們委託給另一個 Less(),但你必須保證 Len() 和 Swap() 是兼容的。而且這樣的代碼看起來很奇怪,轉型看起來像是在調用函數:

sort.Sort(sort.Reverse(UsersByLastSignedInAt(users)))

9. 缺少泛型。

我真的不想使用一門無法實現 Stack 泛型類的語言。臨時的解決方案是使用 append() 函數替代,但現在都什麼年代了,我可不想寫像下面這樣的代碼:

stack = append(stack, object)
object = stack[len(stack) - 1]
stack = stack[:len(stack) - 1]

我很好奇究竟有多少第三方庫使用了 interface{}。可見 Go 語言的類型系統設計得非常糟糕。

10. 這是個小問題,但足以說明 Go 語言設計者沒有完全站在程序員的角度考慮問題。

append() 函數用於擴展一個數組,然後返回新數組:

users = append(users, newUser)

但下面這行代碼總是能夠調用成功:

append(users, newUser)

append() 函數在可能的情況下進行原地數組修改,如果沒有足夠的空間就返回一個新的數組。這樣的 API 設計真是再糟糕不過了。有多少 bug 是因為忘記把結果賦值給變量引起的?有很多。因為即使是在測試時也不一定會觸發數組調整大小(這裡需要說明一下,後來他們修改了編譯器,如果 append() 函數沒有被賦值給變量,就拋出錯誤)。

總 結

這是我個人對使用 Go 語言的一些建議:如果你的程序很小,基本上可以說清楚要實現什麼功能,並且不會與太多外部數據(數據庫、Web 等)打交道,那麼使用 Go 語言是沒有問題的。如果程序很大,有很複雜的數據結構,或者需要處理大量的外部數據,那麼 Go 語言的類型系統會讓你抓狂,你最好選擇其他靜態類型的語言(類型系統比較完善)或者動態語言(不會礙手礙腳)。

網友熱議

雖然這篇文章並非最近剛剛發佈,但它這一次登上 HackerNews 後依然引發了網友的熱烈討論,收穫了數百個討論並在很短的時間裡再次登上 HackerNews 熱度榜。有的網友對作者的觀點表示認同,並表示雖然會將 Go 語言作為一種備用的編程語言,但如無必要不會再去用它。有的網友則覺得作者提出的大部分缺點都不是問題,並希望 Go 語言保持初心,不要隨意修改。以下是我們整理的網友精彩評論。

網友lostingthefight:

我從 2015 年開始就在生產環境中使用 Go 語言。說實話,除了三元運算符,其他的對我來說都不是問題。我主要從事 REST API 方面的開發,所以面對的場景可能不太一樣。首字母大寫和接口實現問題對我來說也不是個事。Go 語言提供的一些特性在我所使用過的語言中是最好的。再配合一個好的編輯器,就不會錯過任何異常。不過不管怎樣,Go 語言並不完美。有時候 Go 例程很難追蹤,而且對於大型項目來說,模塊過度是個麻煩事。不過,如果有得選擇,我還是不會回到 Java、C#、PHP 或者 NodeJS。

網友kstenerud:

即使是在中型項目中,我也受到了這些問題的困擾。未使用的導入和變量會導致編譯錯誤,這點實在很令人厭煩,所以不得不給編譯器打個補丁(https://github.com/kstenerud/go),把它們變成警告,而不是錯誤。

網友cr0sh:

離最後一次使用 Go 語言已經很長一段時間了。我還記得當初學習 Go 語言的經歷。我和我的同事被安排為我們的僱主(一家雲服務提供商)開發一個接口,允許 Rancher(或者 Rancher 的客戶端,具體忘了是哪個了)使用我們的後端系統(使用 PHP、Java 和 Bash 開發的)來分配服務器。Rancher 是使用 Go 語言開發的,但我們都沒接觸過 Go 語言,我們都是 PHP 開發者,於是我們開始學習 Go 語言。我們大概花了一個禮拜時間學習 Go 語言,一個月之後,我們就開發出了一個可運行的庫,還帶有文檔和測試代碼。但是整個開發過程與文章中所寫的差不多(這裡略去若干罵人的話)……我們已經習慣了在 PHP 中放一些臨時用的代碼,比如為了試驗、調試等原因。但是,Go 語言不允許我們這麼做。要想編譯通過,必須清理掉這些東西,這讓我們感到很抓狂,而且日復一日,一週又一週,然後:我們釋然了。我們可以理解為什麼 Go 語言的設計者要這樣設計,我們甚至希望 PHP 也這麼做。我們後來沒有再隨意亂放臨時代碼,因為這些代碼在後面有可能會給我們帶來麻煩。Go 語言的這種設計確實給開發添加了難度,但另一方面卻可以幫我們避免出現更多的錯誤,或者在未來出現更多的 bug,並讓代碼變得更容易維護。但不管怎樣,我不用 Go 語言已經有好幾年時間了,我不再需要它了。但如果有必要,我還是會用它。或許,這幾年 Go 語言發生了很多變化,不過也有可能變化並不大。無論如何,我從那次經歷中學到了一個道理:在得到你想要的東西之前,必須經歷痛苦和掙扎。我體驗了一門非常獨特的語言,我也因此變成一個更好的開發者。

網友sdegutis:

客觀來說,首字母大寫是個問題,特別是在改變了可見性之後需要重構代碼。不過,使用一個好的 IDE 可以減輕這方面的工作量。更重要的問題是 Go 語言設計者似乎無法體會慣例的重要性。我過去十年所使用的編程語言都鼓勵開發者使用變量、類名和常量慣例。這讓我想起了那些想要讓人們使用 CE(公元)和 BCE(公元前)代替 AD(公元另一種說法)和 BC(公元前另一種說法)的人,他們忽略了後者的習慣性和相關性,就好像他們生活在真空中。我不知道該怎麼說,但這是我不喜歡 Go 語言最主要的原因。有人說 Go 語言是一門借鑑了 C 語言特點的新語言。但我覺得這種說法有點誇張,就好像是說:“現在是 1970 年,C 語言不存在,後面 49 年的事情都還沒有發生”。

網友dawkins:

我從 2012 年就開始在生產環境中使用 Go 語言,我覺得它是一門非常棒的語言。除了文中提到的第八點之外,其他對我來說都不是問題。Go 語言設計者把這門語言設計成這樣,我是感到滿意的,但讓我感到困擾的是最近做出的一些變更:模塊和 Go 2 提案。我希望他們能夠保持最初的願景不變。

網友lkramer:

文章提到的問題似乎都很合理,但它們都不足以讓我討厭這門語言。或許首字母大寫也是困擾我的一個問題,或許設計者當初可能考慮到可以通過 IDE 來減輕重構工作。但不管怎樣,要把一些東西從私有變成非私有要修改很多文件可能不是一個好的設計。我在錯誤處理方面也吃過幾次苦頭。我不太喜歡異常,但這個問題可以通過顯式忽略變量來解決。Go 語言並不完美,但從我的經驗來看,沒有什麼比 Go 語言更適合用來開發微服務了。

網友diamondo25:

文章提到的問題都不算是問題。我希望 Go 語言可以這樣一路走下去,不要走回老路或者像 Scala 過去幾年所做的那樣……

網友gerbilly:

我只想說一句話:是否選擇一門語言,不要看它的設計,要看它是否可以解決你的問題。

網友dbt00:

Go 語言確實不完美,但我覺得在解決同樣的問題時,它比 Java 或 C++ 更高效。對於文中提到的第二點,我並不喜歡作者舉的例子。我覺得不管在任何一門語言中都不應該定義這種容易產生混淆的接口。所以,這一點對我來說也不是問題。對於第三點,我自己開發了一個小插件,用來檢查錯誤。如果你要對一個片段進行排序,sort.Slice 比 sort.Interface 更好。泛型已經被確認是個問題,解決方案正在路上……

你現在正在使用 Go 語言嗎?你是否喜歡 Go 語言?你認為作者提出的這 10 個理由是 Go 語言的缺點嗎?Go 語言有沒有什麼問題正在困擾著你?歡迎在評論區留下你的觀點和故事。

英文原文:

https://www.teamten.com/lawrence/writings/why-i-dont-like-go.html

HackerNews 網站討論:

https://news.ycombinator.com/item?id=20166806

Go 語言相關文章回顧:

《再見,Python!你好,Go 語言》

我不喜歡Go語言的十個理由

看全文,見瞭解更多哦~

"

相關推薦

推薦中...