為什麼 Go 語言如此不受待見?

在 Quora 上,有個問題是比較 D/Rust/Go/Nim 等語言的表現,幾乎一致地認為 Go 是最搓的,Rust 備受好評。各位看看何解?

Of the Emerging Systems Languages Rust, D, Go and Nimrod, Which Is the Strongest Language and Why?

他們有一個觀點,能夠直接操作硬體的才被定義為系統級語言,而另外定義是適用於 web 後端或者分散式。Go 由於其 gc 而被直接否定。


Rust 和 Nim 確實好呀

Rust 可以說是 D 語言二代目, 沒有 D 里的一些經驗主義設計, 而且更函數式, 作為 a better C++ 當之無愧. Pattern matching, Block, Generic 這些東西, Go 有么? 不好的地方是集成 feature 略貪心, 指針那麼多類型是有道理但是學習者容易被嚇跑.

Nim 不是函數式的, 但 Nim 支持衛生宏, 可以做 AST 重寫, 可以自定編譯規則, 是靜態語言中的黑客語言有木有! 自定編譯規則甚至可以編譯出比 C 代碼還快的結果, 作為 a better C 當之無愧. 人家 GC 可以手動步進的啊, 想要什麼 feature 自己加(list comprehension? 沒問題), 加個 const 就可以做編譯期計算了(想想 C++ 和 D 里複雜難以掌握的 template 和 static if 多蛋疼), 改寫 AST 的 pattern language 也是簡單易懂(想想 Java 的 annotation processing tool 怎麼用的就蛋碎...), 更重要的一點: 沒有那麼多哲學騎著你禁止你怎麼怎麼做, Go 能么?

人類思維有個巨大的缺點就是從眾定勢, 當然社區大了開發者多了語言會更容易成熟和變得實用, 但如果更多人懂得多了解學習, 理性比較而不是跟風, 現在的編程語言可以發展得更好.


回 @Irons Du , 不是為了反對他的答案,是因為基於這些問題,能解釋 Go 不受待見的其中一個原因:Go 面對的問題和整個解決思路跟 Google 軟體的規模相關,而這個規模是罕見的。20 億行源碼放在一個統一的代碼庫,全部主幹提交,理論上代碼庫里任何兩點都可以互相調用,幾萬個工程師(我是其中一名豬隊友)在全球各個時區協同。Why Google Stores Billions of Lines of Code in a Single Repository. 這個設計前提導致了同樣被黑得很慘的 C++ Style Guide (The Philosophy of Google"s C++ Code) 和 Go 的一些看著很奇葩的設計點。

另外這個軟體規模是一個問題,不是什麼值得炫耀的東西。Go 為解決這些問題的設計,並不一定適合其他場景。回答這個問題本身,這裡也不是說 Go 有多好,只是可以分享一些「為什麼」,很有趣的設計權衡,例如 Quora 原文提到的 Go 幾乎忽略了所有現代 PL 研究成果,但實際上這些成果在這個規模上還沒能很好地工作。關於 Go 為什麼是(或不是)系統編程語言的問題,我可以另外寫一篇。

1:你能輕鬆知道哪些struct繼承(實現)了哪些interface么?

能,Go guru. 2016-talks/slides.pdf at master · gophercon/2016-talks · GitHub 在超大軟體庫上一樣很順。顯式 implements 聲明上規模後會有問題,多餘的依賴關係是其中之一,下面有關於依賴的更詳細討論。

2:你能輕鬆知道struct有哪些"成員函數"么?

能,godoc 啊

這兩點正好說明了 Go 極端重視工具的設計思路,工具能解決大代碼庫上源代碼級別無法解決的問題,比如全代碼庫索引、重構,計算改動影響範圍觸發集成測試等等。這裡面也必須有權衡,例如,要為這個規模寫編譯器和各種工具,你最好別搞複雜的類型系統,不然事情會很困難。

3:手動維護defer能比RAII輕鬆?

RAII 很難。C++ destructor + exception, 這裡的 exception 包括處理 destructor 的異常安全和 destructor 自己真的需要拋異常的情況。還有如果在 destructor 里放了重型操作,比如 flush 硬碟,defer 至少讓你清楚地看到這種重操作會在哪裡跑。這些問題當然都可以用很仔細的設計避免,但是在有幾萬個豬隊友的時候,不要指望每個人都能做出好設計。

4:package只有一個層次

如果是指不能只 import 一個父節點而要顯式 import 所有葉子節點。這是用來控制 dependency 的,不必要的 dependency 在大軟體庫是個嚴重問題。Go 奇葩的 import 多餘 package 直接編譯錯誤的規則也是這個目的。

5:訪問控制只能限定在package之外。

個人體驗,它省掉了很多語法規則,還工作得很好。有點不方便的是你看它 call 一個私有函數,但是在同一個文件里是找不到這個函數的定義的,它可能在同一個 package 的另一個文件里。這個是用工具補足的 —— 在內部的 code search 工具里我沒感覺不方便,在 github 沒有交叉引用的情況下看代碼就比較鬱悶。

6:基於源代碼的開發(復用),這是否違背了以前書上說的實現隱藏(只暴露介面)?

沒,主要是因為 Google 統一代碼庫,Go 一開始壓根沒考慮二進位庫發布的問題。這跟軟體工程的隱藏實現是兩回事。依賴版本管理問題同理,因為統一代碼庫+全主幹提交,這個問題在 Google 是不存在的…… 當然問題就是問題,現在外部使用越來越多他們也在逐步補鍋了。

7:推崇error作為返回值是不對的。另外(panic+recover)對比下C++在C之上添加的異常處理(+RAII)的類型安全

推薦一篇微軟 Midori 項目 (Rethinking the software stack) 語言 leader 的 Joe Duffy - The Error Model (超長)。error 功能不夠好,但 C++ 和 Java 的 exception 機制在上規模後也有無法解決的工程和性能的問題,Optional是好,但是語言就要變複雜,這裡面有 tradeoff. 另外,「異常安全」是個看起來遵守規則寫就可以的簡單事情,但實際上非常困難,比如事務的回滾,文中也有專門描述。


Go除了goroutine之外,其他基本所有的東西都在倒退,只是有一個牛逼的爹而已

最簡單一點,一個static language不支持范型鬧哪樣??語法上標新立異太多,丑的不能直視

查查歷史看看Go設計了多久,Rust設計了多久,這差距太大了

對比看看Rust的feature set,以及精良程度,完爆Go幾十條街

不同意很多人說的,Java在剛剛出現的時候絕對是非常先進的,Go剛出現的時候就沒什麼了不起的

我和公司裡面一個用Go的team稍微合作過一下,其中一個工程師的感受就是,Go在代碼重用,工具鏈方面非常差,各種interface{}到處飛,goroutine用起來經常要debug幾千個routine跑來跑去也非常崩潰,但也沒辦法,我們都習慣了,這麼多代碼已經寫了,最開始從ruby轉型選擇Go那個哥們兒已經走了,留下一堆爛攤子


退一萬步來說呢,golang挫又如何呢?現在有了Docker,為golang大大的續命了一下。我們有客戶想要在zlinux使用Docker,然後發現沒有這個平台的go編譯器,於是我們就要開始想辦法做go編譯器(客戶就是上帝這句話不是隨便說說的)。而我最近也在看go,覺得它更吸引Python和Ruby的人是有道理的,雖然go其實是想吸引C++。然而事實上,Rust或許會更吸引C++的開發者一些。

決定一個語言的流行度(或者說火不火)也往往不是語言本身,而是其它的。如Objective-C,我一直覺得語法很醜,但是之前它就是iOS開發的官方語言,你想要開發iOS的APP,你就要用它,iOS火它就火。而如果有一天Rust可以火起來,我相信也不是因為語言本身,而是有一個讓它火起來的東西(servo?)

至於D語言,雖然它一出來就說我要幹掉C,我要幹掉C++,然而和眾多號稱要幹掉C和C++的語言一樣,都是歡聲笑語中打出GG,一切歸於雲煙。


都已經流行成這樣了還不受待見啊……

這東西就是一個工程工具,各種好用,但是從設計角度講各種粗糙,沒必要過度高估。


mozilla 的工程師有放出來過一個 ppt 說為什麼從 python 轉 go 後來又轉回 python 的:

https://docs.google.com/presentation/d/1LO_WI3N-3p2Wp9PDWyv5B6EGFZ8XTOTNJ7Hd40WOUHo/mobilepresent?pli=1slide=id.g70b0035b2_1_168

個人感覺裡面比較 critical 的地方主要是:

  • 沒有異常也就出錯時沒調用棧信息,線上出問題會懵,要麼 gdb 要麼自己補 print
  • go 專家也很難寫對 goroutine 不泄露的代碼,這裡面該是有固有複雜性的
  • 測試難寫,理論上強類型語言比弱類型語言更容易寫對,然而語言的反射機製做不到位的話 mock 起來超麻煩,做高測試覆蓋率反而不如 python 這類弱類型語言容易


在一家省分行用go每天處理二千萬條數據入數據倉庫做數據分析,後台用oci連oracle,前台web只用了gorilla的mux庫,三個月來系統很穩定,數據處理速度及報表交互速度很快。做過一個與核心對接的交易查詢系統,使用cgo與核心中間件對接,也很穩定,資料庫mysql。還用go做了一個預算管理、一個伺服器資源監控系統和一個基於activity的workflow,做完的感覺就是我今後很長時間還是會用go。以前做項目用過java,Python。Java的缺點是語法太啰嗦,虛擬機還得調優。Python不能充分利用多核,部署也麻煩。golang優點很明顯:語法像Python一樣靈活優雅,後期運維部署簡單方便到讓我感動(經過python部署折磨後),沒有泛型之類的語法我也基本把上述系統的業務邏輯都完成了,我不是個語言控,語言不必大而全,複雜了我也玩兒不轉,也不需要語法糖對別人炫耀(時間長了我也看不懂),對於我來說就是把系統業務邏輯快速完成,開發部署越簡單越好,系統一定要穩定。golang滿足了我一切要求,真的有它就go了。


1:你能輕鬆知道哪些struct繼承(實現)了哪些interface么?

2:你能輕鬆知道struct有哪些"成員函數"么?

3:手動維護defer能比RAII輕鬆?更安全?怕不怕順序問題?怕不怕寫露了?而且是函數作用域的。

4:package只有一個層次,容易出現衝突。

5:訪問控制只能限定在package之外。而且沒有static 函數等等。

6:基於源代碼的開發(復用),這是否違背了以前書上說的實現隱藏(只暴露介面)?

7:推崇error作為返回值是不對的。另外(panic+recover)對比下C++在C之上添加的異常處理(+RAII)的類型安全, defer 也沒有顯式的try catch直觀和精確控制。

8:go是入門簡單,學好難。難在多線程編程。Go能更容易寫出多線程程序。但對於一個需求明確的任務,我並不覺得通過仔細斟酌設計的C++多線程程序比Go差,反而更好,很多地方更容易控制。當然這需要能力。但既然沒得能力,我相信同樣也寫不好Go的多線程程序。

-----------------

ps,前[1-5]對於小項目問題不大。


作為系統編程語言不支持自定義內存分配,作為高級語言用的都是老式 C語言的思路,對象和函數式支持的太弱,沒有合適的包依賴系統,周邊社區的庫質量參差不齊,沒有很好用的IDE ,一些狂熱粉又起到了一粉頂十黑的作用。


幾個實際例子。

goroutine泄漏。goroutine雖然方便,但是粗心的開發者用爽了之後,會濫用goroutine,導致和內存泄露類似的問題(再搞一個垃圾goroutine回收機制?2333)。

官方包bug。之前用cgo封了個很簡單的HttpClient給C調用,go1.5的gc在C程序中不完美,導致有時鏈接不會正常釋放,程序還會時不時hang在os.yield上。go1.6更新日誌的第一句就是cgo完美支持gc,但是我試了一下這個問題依然存在。還有什麼不支持低版本ld(去go源碼中注釋掉一行代碼,然後重新編譯go就能「支持」了)。

官方包文檔。http包,transport,client這些類如果想要自己訂製一些功能,那麼最好要搞清楚什麼類開了什麼goroutine,是不是埠需要手動close,goroutine有沒有shutdown。這些文檔里沒有說。

風格。我真的很不喜歡寫一句話就寫n句if err!=nil{…},而且寫完之後還要想盡辦法去構造單元測試來覆蓋這個分支。如果你覺得這個地方實在是不會出現err,那麼就用_來吃掉這個err吧,然而以後每個看代碼的人都會看到這個_,然後想想為什麼這裡可以吃掉這個err,浪費時間不喜歡。太過於嚴謹,需要更折中一些,個人覺得。


人家問的是 Systems languages,不是 Languages!先看看標題,不要一來就站立場。

Go 不管人家設計的時候有沒有這樣的定位,反正現在社區是沒有的。而 Rust 本身就是在這種定位下設計的,社區也很重視。

你在知乎上問 Julia 和 PHP 哪個更適合科學計算,PHP 還不是會被一致否定?儘管大家都知道 PHP 是世界上最好的語言,這條公理,但仍然不影響在科學計算的語境下否定最好的語言。

人家問題的語境下 Go 就純屬打醬油的,術業有專攻而已。

看看人家的第一句話,重點就在於什麼是系統編程語言:

First of all, it depends on what you mean by systems language. Rob Pike et al. have repurposed the term to mean distributed or web backend systems. I prefer the original definition which refers to operating and controlling hardware.

當然一個沒有模式匹配,ADT,沒有泛型和宏,靠 if err != nil 來進行錯誤處理的,新的靜態類型語言我是不想碰的啦。


只說我個人對go的意見,由於用得不深可能有些說得不對的地方

語言設計雖然要有創新,但語法這種東西搞太多創新反而會提高學習成本,比如在C++和go中切換一陣子,常常寫錯string s和s string,當然這是一個喜好問題,花點力氣轉過來也不是困難

語法過於封閉和霸道,譬如map、range這種可以作為一個庫或方法的都實現為關鍵字,當然,你說這些常用,那沒啥問題,但是我們能不能對於自定義的結構,定義它自身的hash、eq來作為map的key,以及能不能定義自己的方法讓它可以被range呢,貌似沒找到辦法,不是很確定,如果有請告訴我呀

非入侵介面是有些優勢,但會帶來比較大的效率損耗,雖然1.7出來後整體速度提了一截,但用不用interface的比對還是差距比較大的,另外這個設計本身的一些缺陷網上也有文章專門敘述,略了

沒泛型,比如,怎麼定義一個可以和自身比較的類型的通用介面呢,即類似Java中&&>這種,如果用interface的話,貌似不能限定「只能和自身類型」,那隻好運行時動態檢查?我因為這個問題,看了sort庫的代碼,發現是從另一個角度繞過的,而且sort這麼搞只能有效支持類似數組的結構了,那我想寫個通用紅黑樹怎麼設計介面呢,感覺比較困難

錯誤處理很多人吐槽過了。。。其實我倒是沒那麼強烈的意見,就是寫一些小腳本太啰嗦

cgo的性能,大部分語言的C擴展很多時候是用來改寫核心模塊而提高效率,go卻不是,cgo的設計是有自己的苦衷,但能不能提供一種不走環境切換的選擇呢


編譯器/工具鏈也學互聯網行業跟風拿用戶當測試,簡直一點素質沒有。


用過Go最大的體會是,Go社區的風氣不是很好,發布半成品成風。

也許有人會說因為Go社區還年輕,但是Node社區也很年輕,雖然很多庫功能很弱,但是完成了的功能都是比較完備的。

感覺Go如果沒有Google當爹根本不會有人用(地圖炮是不是放的有點過...)。


盛名之下,其實難符。


世界上只有兩種編程語言:

沒人用的 和 被人噴的

╮(╯▽╰)╭


一直認為 只有最適合自己項目的語言 沒有最好的語言, 看來我二逼了。。。。

選個晶元還得選型呢。。。雖然很多情況下晶元沒得選 但沒得選不是說明已經選型好了嗎

不知道爭論這些有什麼意義。

就好比XP再不比win8好, 不是虛擬機上已經完美找到它生存的意義嗎? 隨便一個不兼容的軟體 ,開個低資源佔用的XP虛擬機,完美得很。。。

哎 哪個語言是最好的語言這個梗什麼時候才能變成 我這個項目最適合用哪種語言的討論啊。。。。

你們就選個最好的語言 寫一個最完美的代碼唄,看你項目死不死。。。

大神太多 晚輩匿了。。


一粉頂十黑


連個好用的IDE和debugger都沒有。。。。。。。


謝邀

Go 是不錯的語言,那是和以有的語言比。但是的確不如 Rust 啊。


推薦閱讀:

Golang 里的fatal error怎麼處理?
golang里gc相關的write barrier(寫屏障)是個什麼樣的過程或者概念?
為什麼go語言gc的時候要暫停整個程序?
如何評價 Go for android 或 Swift for web 這種現象?
為啥 Erlang 沒有像 Go、Scala 語言那樣崛起?

TAG:編程語言 | Go語言 |