Go語言將接管程式設計世界的五個原因 | Brad

banq 發表於 2022-10-31
Go

Go 程式語言已經存在了十多年,並且逐漸流行起來。以下是一些原因,以及為什麼您可能會發現自己想用 Go 編寫下一個專案。

1. 恰到好處的執行時間
程式語言的“執行時”是它附帶的程式碼,是支援語言本身特性所必需的。
Go 的執行時間比例如 C++ 大得多,但這是有充分理由的。
當我檢視語言中包含的執行時功能時,我看到了一個模式:

  • 垃圾收集——你不必手動分配和釋放,Go 會為你處理這些
  • Goroutines — 高效的多執行緒和 I/O
  • Channels——用於在 goroutine 之間推送資料
  • 介面——簡約但高效的動態型別斷言
  • 切片——使用方式與在另一種語言中使用陣列的方式相同,但旨在更有效地處理分配(在很多情況下是懶惰的)
  • Maps — 語言中內建的良好的舊鍵值雜湊對映,語法簡潔
  • 指標——就像 C 語言一樣,除了沒有指標運算,值與指向它們的指標都被清楚地指出,但沒有導致分段錯誤和其他崩潰的東西
  • 型別推斷的型別安全——一切都有一個型別,但有一些簡寫方式不必在每種情況下都寫出來(例如,“a := b”使“a”與“b”的型別一致)
  • 該語言也明顯沒有某些東西,例如異常和elvis運算子“?:”。


這些是幾乎每個應用程式都需要的東西,因此被認為足夠重要,可以放入執行時。但是,他們也對自己新增的內容表現出一些剋制,並專注於“物超所值”的功能。

2.Go程式碼更加冗長
是的,你沒看錯,Go程式碼更節制是件好事。要了解原因,你必須考慮使程式碼不那麼囉嗦的原因和手段,並看看它的代價。

從表面上看,短一點似乎更好,對嗎?當你可以寫"=>"時,為什麼還要寫 "函式"?當你可以使用"{}"時,為什麼還要寫出 "Object "呢?

答案很簡單。認知的開銷。或者,換一種說法,每當你增加一個新的功能,人們就不得不記住和思考另一件事。

隨著時間的推移,這種影響會越來越嚴重,因為新功能的加入,一種語言的程式碼曾經是最新的,現在因為所有的新功能的加入而變得過時。今天寫的C++程式碼看起來與十年前有很大不同。在這種情況下,問題不在於語言本身,而在於最佳實踐和所使用的通用庫,但重點是一樣的:雖然事情在改進,人們在尋找更好的方法來做事情,這是好事,但發明新的方法來做同樣的事情會令人厭煩,並增加不必要的複雜性。

有時候,我覺得需要有人告訴Javascript的人,在語言中不斷新增東西不應該是某人的工作。也許他們應該僱人開始刪除一些東西。只是一個想法。

在其他語言中,我認為其他的便利條件是一種糟糕的權衡,比如異常。在Java(和JS)中,你可以用 "try "來包圍一個巨大的程式碼塊,然後給一個程式碼塊來處理其中發生的任何錯誤。那麼你認為大多數新手開發者是如何利用 "try "和 "catch "的呢?你猜對了,就是把一些行為不端的程式碼塊拿出來,把錯誤消音。試圖寫出好的、可靠的軟體就這麼多了。

Go透過允許函式返回多個值來解決這個問題,按照慣例,其中一個值通常是一個錯誤。然後你就可以檢查這個錯誤。你知道的,用一個 "if "語句。它很難看,很囉嗦,很可怕,孩子們在它的大壞蛋囉嗦中跑來跑去。然而,它工作得非常好。當你抱怨完不得不輸入所有這些 "if err != nil {"行時,谷歌一下"[你的編輯器名稱]片段",看看如何為自己製作一個快捷方式。

3.現在有了泛型,就沒什麼可抱怨的了
很久以來,我一直聽到人們不想寫Go程式碼,因為它沒有泛型。而我真的很高興他們增加了這個功能。不是因為我想使用它,而是因為我不喜歡聽人們抱怨它。泛型是這些表面上相當簡單的東西之一,但在引擎蓋下有很多細微的差別和隱藏的複雜性。考慮到這樣一個事實:C++模板和Java泛型在語法上看起來非常相似,但它們在引擎蓋下的實現卻完全不同。這種複雜性你作為開發者可以忽略,但對語言本身有巨大的維護影響。不管怎麼說,既然已經做了,人們就不能再抱怨了,可以去發現這樣一個事實:一旦寫好的程式碼中,通常只有一小部分需要或受益於泛型。

不要誤會我的意思,將型別作為引數在特定情況下是非常有用的。我只是認為這些情況比人們通常認為的 "唉,Go沒有泛型 "要少得多。

4.令人敬畏的構建工具
僅僅是資料夾中的檔案和一個簡單的go.mod檔案就可以在不同的系統上以完全相同的原始碼輸入產生可靠的構建,這一事實聽起來很簡單,也很明顯,但它實際上正是其他構建系統所做不到的。試著構建一個node.js專案,等待6個月,再執行 "npm ci",看看你會得到什麼。構建問題是一個持續的痛苦來源,而Go終於把這個問題解決了。

這裡的關鍵概念是,一組相容的API得到一個匯入路徑,以及這個想法(https://research.swtch.com/vgo-mvs)[最小版本選擇]。

再進一步分解一下。第一個概念是一個主要的概念,也是大多數其他版本系統所錯誤的概念。這個概念是,一個模組的每個獨特的不相容的版本應該有一個獨特的匯入路徑。換句話說,如果你有版本1的庫X和版本2的庫X,你猜怎麼著?這些都是不一樣的東西,因此需要不同的匯入路徑。在Go模組中,他們引入了在匯入路徑中附加"/v2 "的想法,以對應模組的版本2,等等。你可以閱讀一下細節,有一些零碎的東西需要學習,但我認為他們在這裡得到了正確的核心思想。如果你對一個庫做了破壞性的修改,它就會得到一個不同的匯入路徑。這種簡單的做法具有重要的副作用,可以極大地提高可靠性並減少構建的混亂。

一旦你有了這個概念,那麼最小版本選擇就更進一步了,比如說我們不應該只是 "使用最新的2.x "庫,而是應該手動升級依賴關係,只使用在構建配置(go.mod)中指明的測試版本的庫。這樣一來,如果你今天構建了一個軟體,明天執行同樣的構建,你就能保證得到相同的輸出(使用了相同的確切版本作為輸入)。現在,我們當然想跟上升級和安全補丁之類的東西,但我們的想法是這應該明確地完成,而不是隨機地作為構建過程的一部分。

與其他許多構建系統相比,這些變化使構建Go程式成為一個夢想。

5.大型專案的型別安全是必須的
很多其他語言也有型別安全,但JavaScript和Python是很好的例子,這些語言對小專案來說很有成效,但由於缺乏型別安全,很容易失控。

現代編輯器透過為常見的情況提供合理的錯誤符號來減輕這種痛苦,即使在像JS和Python這樣型別不安全的語言中也是如此。但這並不能改變這樣一個事實:隨著你的應用程式的複雜性增加,如果你使用的語言除了在執行時沒有對任何欄位或方法的訪問進行檢查,你遲早會寫出一些目前看來還不錯的程式碼,然後在生產中突然爆發,而且是在最糟糕的時候,因為一些愚蠢的錯字。如果有一個編譯器和一個型別安全的語言,這個錯字是可以避免的。在編輯程式碼時,你也能得到同樣的好處。在編譯步驟中出現 "a.SomeThing() "的錯誤(因為它應該是 "a.Something()")可以節省你的時間,因為你不需要執行那行程式碼來發現問題,你只需要編譯。

Go的型別系統雖然因其與其他語言的差異而備受爭議,但它具有你所期望的其他型別系統的所有主要優點。用它們來做好事。

總結
總而言之,雖然它只有 10 年的歷史,但 Go 在成為許多團隊解決業務程式設計問題的事實上的標準方面已經取得了重大進展。它真的會“接管”嗎?說不定呢。但我認為有很多令人信服的論據使它穩步繼續發展。而羅馬也不是一天建成的。