1. 程式人生 > 實用技巧 >也許是最客觀、全面的比較 Rust 與 Go:都想把 Rust 也學一下

也許是最客觀、全面的比較 Rust 與 Go:都想把 Rust 也學一下

最近一年,將 Rust 和 Go 進行比較的不少,但不少都不公正,帶感情色彩。而這篇文章客觀、全面的分析對比了 Rust 和 Go,讓你具體專案時選擇最合適的。

Rust 還是 Go,哪個更好?你應該為下一個專案選擇哪種語言,為什麼?兩者在效能,簡單性,安全性,功能,規模和併發性等方面如何比較?它們有什麼共同點,並且在根本上有何不同?來自For the Go of Love[1]系列圖書的作者,友好而公正的比較 Rust 和 Golang。

Rust 和 Go 都很棒

首先,非常重要的一點是,Go 和 Rust 都是絕對優秀的程式語言。它們是現代的,強大的,被廣泛採用的,並且具有出色的效能。你可能已經閱讀了一些文章和部落格文章,目的是說服 Go 比 Rust 更好,反之亦然。但這確實沒有道理;每種程式語言都代表一組權衡。每種語言針對不同的事物進行了優化,因此,應根據適合你的語言以及你要解決的問題來確定語言的選擇。

在本文中,我將簡要概述我認為 Go 是理想的選擇,以及我認為 Rust 是更好的選擇的地方。不過,理想情況下,你應該對這兩種語言都有一定的瞭解。儘管它們的語法和樣式差異很大,但 Rust 和 Go 都是用於構建軟體的一流工具。話雖如此,讓我們仔細看看這兩種語言。

相似之處

Rust 和 Go 有很多共同點,這是你經常聽到他們一起被提及的原因之一。兩種語言的共同目標是什麼?

Rust 是一種專注於安全性和效能的低階靜態型別多正規化程式語言。Gints Dreimanis[2]

Go 是一種開放原始碼程式語言,可輕鬆構建簡單,可靠和高效的軟體。—Golang.org[3]

記憶體安全

Go 和 Rust 都屬於優先考慮記憶體安全性的現代程式語言。數十年來,使用 C 和 C++ 等較舊的語言已經很清楚,導致錯誤和安全漏洞的最大原因之一是不安全或不正確地訪問記憶體。Rust 和 Go 以不同的方式處理此問題,但是兩者的目的都是要比其他有關記憶體管理的語言更聰明,更安全,並幫助你編寫正確且效能良好的程式。

快速,緊湊的可執行檔案

它們都是編譯語言,這意味著你的程式直接轉換為可執行的機器程式碼,因此你可以將程式作為單個二進位制檔案進行部署;與 Python 和 Ruby 等解釋型語言不同,你無需隨程式一起分發直譯器,大量庫和依賴項,這是一大優勢。與解釋型語言相比,這也使 Rust 和 Go 程式都非常快。

通用語言

Rust 和 Go 都是功能強大,可擴充套件的通用程式語言,你可以使用它們來開發各種現代軟體,從Web應用程式到分散式微服務,或者從嵌入式微控制器到移動應用程式。兩者都具有出色的標準庫和蓬勃發展的第三方生態系統,以及強大的商業支援和龐大的使用者群。它們都已經存在了很多年,並將在未來幾年繼續被廣泛使用。今天學習 Go 或 Rust 將是你的時間和精力的明智投資。

務實(Pragmatic)的程式設計風格

兩種語言都不是純函式式語言(例如 Scala 或 Elixir),也不是全面面向物件的語言(例如 Java 和 C#)。相反,儘管 Go 和 Rust 都具有與函式和麵向物件的程式設計相關的功能,但它們都是務實的語言,旨在以最合適的方式解決問題,而不是強迫你採用特定的處理方式。(不過,如果你喜歡函數語言程式設計風格,則在 Rust 中會發現更多的函式式特性,因為 Rust 的函式式功能比 Go 多得多。)

我們可以討論什麼是“面向物件”語言,但是公平地說,Go 或 Rust 中都沒有 C++,Java 或 C# 使用者期望的面向物件程式設計風格。—Jack Mott

大規模發展

Rust 和 Go 都具有一些有用的特性,這使其適合於大型程式設計,包括大型團隊,大型程式碼庫,或兩者兼而有之。

例如,儘管 C 程式設計師多年來一直在爭論括號的位置,以及是否應使用製表符或空格使程式碼縮排,但 Rust 和 Go 都通過使用標準格式工具(gofmt 用於 Go ,rustfmt 用於 Rust)完全消除了此類問題。它使用規範樣式自動格式化你的程式碼。並不是說這種特殊的樣式本身如此出色:而是 Rust 和 Go 程式設計師所欣賞的標準化。

gofmt 的風格不是每個人的最愛,但 gofmt 是每個人的最愛。Rob Pike[4]

兩種語言得分很高的另一個領域是構建管道(build pipeline)。兩者都具有出色的內建高效能標準構建和依賴管理工具。不再需要為複雜的第三方構建系統而費力,也不必每兩年學習一次新的。

在我早期的職業生涯中,具有 Java 和 Ruby 背景的 Go 和 Rust 程式碼構建工作似乎使我無法承受。當我在 Google 時,遇到用 Go 編寫的服務感到很欣慰,因為我知道它易於構建和執行。Rust 的情況也是如此,儘管我只是在較小的規模上進行了研究。我希望無限可配置的構建系統的日子已經一去不復返了,所有語言都附帶了它們自己專用的構建工具,這些工具可以直接使用。Sam Rose[5]

那有什麼大驚小怪的?

考慮到所有這些,並且看到這兩種語言的設計和功能如此強大,你可能想知道所有的聖戰是關於什麼的(我也是)。人們為什麼對 “Go vs Rust” 如此大驚小怪,陷入憤怒的社交媒體爭吵中,並寫了很長的部落格文章,內容涉及只有白痴才會使用Rust,或者 Go 不是真正的程式語言等等。它可能會讓他們感覺更好,但對於試圖決定要為專案使用哪種語言的人,或者應該學習哪種語言來促進程式設計事業的人,這並不能完全為你提供幫助。明智的人不會根據誰喊得最多而做出重要的選擇。

現在,讓我們繼續探討一些成年人在某些方面可能會比較喜歡一種語言而不是另一種語言的問題。

效能

我們已經說過,Go 和 Rust 都能生成非常快的程式,因為它們被編譯為本機程式碼,而無需通過直譯器或虛擬機器。但是,Rust 的效能特別出色,它可與 C 和 C++ 相媲美(C/C++ 通常被認為是效能最高的編譯語言),但與這些較舊的語言不同,它還提供了記憶體安全性和併發安全性,而執行速度卻基本沒有任何成本。Rust 還允許你建立複雜的抽象,而無需在執行時付出效能損失。

相比之下,儘管 Go 程式的效能也非常好,但是 Go 的主要目的是提高開發速度(包括編譯),而不是提高執行速度。Go 編譯器不會花費很多時間來嘗試生成儘可能高效的機器程式碼;它更關心快速編譯大量程式碼。因此,Rust 通常會在執行時基準測試中擊敗 Go。

Rust 的執行時效能也始終如一且可預測,因為它不使用垃圾回收。Go 的垃圾收集器非常高效,並且經過優化,可以使其 STW 的時間儘可能短(並且在每個新的 Go 版本中都變得更短)。但是垃圾回收不可避免地在程式的行為方式中引入了一些不可預測性,這在某些應用程式(例如嵌入式系統)中可能是一個嚴重的問題。

由於 Rust 旨在使程式設計師能夠完全控制底層硬體,因此有可能將 Rust 程式優化為非常接近機器的最大理論效能。對於執行速度超過所有其他考慮因素的領域(例如遊戲程式設計,作業系統核心,Web 瀏覽器元件和實時控制系統),Rust 使其成為絕佳的選擇。

簡單

如果沒有人能弄清楚如何使用它,那麼程式語言有多快也沒關係。Go 被故意認為是對 C++ 等語言不斷增長的複雜性的一種反應。它的語法很少,關鍵字也不多,而且功能也很少。這意味著學習 Go 語言並不需要很長時間,你可以在其中編寫有用的程式。

Go 非常容易學習。我知道這是一個經常被吹捧的好處,但是我對能夠這麼快地提高生產力感到非常驚訝。多虧了語言,文件和工具,我實際上在兩天之後就編寫了有趣的,可提交的程式碼。—Rust 程式設計師對 Go 的早期印象[6]

這裡的關鍵詞是簡單。當然,簡單(simple)與容易(easy)並不相同,但是簡單的小型語言比複雜的大型語言更容易學習。要做的事情沒有太多不同的方式,因此所有編寫良好的 Go 程式碼看起來都一樣。深入研究不熟悉的服務並瞭解其功能很容易。

fmt.Println("Gopher'sDinerBreakfastMenu")
fordish,price:=rangemenu{
fmt.Println(dish,price)
}

儘管核心語言很小,但 Go 的標準庫功能非常強大。這意味著你的學習曲線還需要包括所需的標準庫部分,而不僅僅是Go語法。另一方面,將功能從語言中移出並移入標準庫意味著你現在可以專注於僅學習與你相關的庫。

Go 還被設計用於具有大型程式碼庫和大型團隊的大規模軟體開發。在這種情況下,重要的是,新開發人員必須儘快上手。

使用 Go,你可以快速完成工作。Go 是我使用過的最具生產力的語言之一。口頭禪是:解決今天的實際問題。Matthias Endler[7]

特性

與其他幾種程式語言相比,Rust 支援更多的複雜特性,因此,你可以用它實現更多的功能。例如,它支援泛型。Devathon[8]

Rust 專門設計為包含許多強大而有用的功能,以幫助程式設計師以最少的程式碼完成最多的工作。例如,Rust 的 match 功能使你可以非常簡潔地編寫靈活的表達邏輯:

fnis_prime(n:u64)->bool{
matchn{
0...1=>false,
_=>!(2..n).any(|d|n%d==0),
}
}

由於 Rust 的功能很多,這意味著有很多東西要學習,尤其是在一開始的時候。但這沒關係:在 C++ 或 Java 中也有很多東西要學習,而且你沒有獲得 Rust 附帶的高階功能,例如記憶體安全性。批評 Rust 是一種複雜的語言,沒有抓住重點:它被設計成具有表現力,這意味著具有許多功能,並且在許多情況下,這是程式語言所需要的。當然,這是一條學習曲線,但是一旦你開始使用它,就可以了。

Rust 為準備接受更復雜的語法和語義(可能會帶來更高的可讀性成本)以換取最大可能的效能的程式設計師,與 C++ 和 D 競爭思想共享。Dave Cheney[9]

併發

大多數語言都對併發程式設計提供某種形式的支援(一次執行多項操作),但是 Go 是專為這項工作而設計的。Go 不使用作業系統執行緒,而是提供了一種輕量級的替代方案:goroutines。每個 goroutine 是一個獨立執行的 Go 函式,Go 排程程式會將其對映到其控制下的 OS 執行緒之一。這意味著排程程式僅使用有限數量的 OS 執行緒即可非常有效地管理大量併發的goroutine。

因此,你可以在一個程式中執行數百萬個併發 goroutine,而不會造成嚴重的效能問題。這使 Go 成為 Web 伺服器和微服務等大規模併發應用程式的理想選擇。

Go 還提供了快速,安全,有效的方式,goroutine 使用 channel 進行通訊和共享資料。Go 的併發支援設計良好,使用起來很愉快。通常很難對併發程式進行推理,而構建可靠,正確的併發程式對任何語言都是一個挑戰。但是,由於它是從一開始就內建在語言中的,而不是事後才想到的,Go 中的併發程式設計簡單、合理、良好的整合進語言中。

Go 使構建易於分解的應用程式變得非常容易,該應用程式在作為一組微服務部署時充分利用了併發性。Rust 也可以做這些事情,但是可以說有點困難。從某些方面來說,Rust 對防止與記憶體相關的安全漏洞的痴迷意味著程式設計師必須竭盡全力來執行使用其他語言(包括 Go)更簡單的任務。Sonya Koptyev[10]

相比之下,Rust 中的併發是一個很新的特性,並且還有待穩定中,但是它的發展非常活躍,因此請留意這塊。例如,Rust 的rayon[11]提供了一種非常優雅且輕巧的方法,可以將順序計算轉換為平行計算。

具有輕量級 Goroutine 和 Channel 語法確實很棒。它確實顯示出語法的威力,即如此小的細節使併發程式設計比其他語言感覺更好。—Rust 程式設計師對 Go 的早期印象[12]

雖然在 Rust 中實現併發程式可能會不太直接,但仍然可以實現,並且這些程式可以利用 Rust 的安全保證。標準庫的 Mutex 類就是一個很好的例子:在 Go 中,你可以忘記在訪問某些東西之前先獲得一個互斥鎖,但是 Rust 不允許你這樣做。

Go 將併發作為第一類概念。這並不是說你無法在 Rust 中找到類似 Go 的併發方式,而是留給程式設計師練習。Dave Cheney[13]

安全性

前面我們已經看到,Go 和 Rust 都以不同的方式來防止與記憶體管理有關的大量常見程式設計錯誤。但是,尤其是 Rust 會竭盡全力確保你不會做本不該做的不安全的事情。

Rust 的程式編輯器非常嚴格且學究(pedantic),它會檢查你使用的每個變數以及引用的每個記憶體地址。它避免了可能的資料爭用情況,並通知你有關未定義行為的資訊。從根本上講,併發和記憶體安全問題根本不可能進入Rust的安全子集。Why Rust?[14]

這會使 Rust 中的程式設計成為幾乎所有其他語言的不同體驗,而且一開始可能具有挑戰性。但對很多人來說,努力工作是值得的。

對我來說,Rust 的主要優點是感覺編譯器成為我的靠山,不會讓任何錯誤漏出(有時感覺像魔術)。—Grzegorz Nosek

包括 Go 在內的許多語言都具有幫助程式設計師避免錯誤的功能,但是 Rust 將其提升到了一個新的高度,因此潛在的錯誤程式甚至無法編譯。

使用 Rust,庫程式設計師可以使用很多工具來防止使用者犯錯誤。Rust 使我們能夠說我們擁有特定的資料。其他任何人都不可能擁有所有權,因此我們知道其他任何人都無法對其進行修改。我想不到曾經有過這麼多工具來防止意外濫用。真是太好了。Sam Rose[15]

對於新手 Rust 程式設計師來說,“與借閱檢查器(borrow checker)打架”是一個常見的症狀,但是在大多數情況下,它發現的問題是程式碼中的真正錯誤(或至少是潛在的錯誤)。這可能會迫使你從根本上重新架構程式,以避免遇到這些問題。當正確性和可靠性是你的重中之重時,這是一件好事。語言不會改變程式設計方式的重點是什麼?當你使用其他語言工作時,Rust 講授的有關安全性的課程也會很有用。

如果選擇 Rust,通常需要該語言提供的保證:防止空指標和資料競爭的安全性,可預測的執行時行為以及對硬體的完全控制。如果你不需要這些功能,Rust 對於你的下一個專案可能不是一個好的選擇。這是因為這些保證要付出一定的代價:學習坡度,時間問題。你將需要學習不良習慣並學習新概念。很有可能,剛開始時,你將與借閱檢查器進行很多鬥爭。Matthias Endler[16]

你發現 Rust 的程式設計模型的挑戰性可能取決於你以前在其他語言中所擁有的經驗。Python 或 Ruby 程式設計師可能會發現它有限制;而其他人可能很高興。

如果你是一位花了數週時間尋找這些語言的記憶體安全性錯誤的 C 或 C++ 程式設計師,那麼你將非常感謝 Rust。“對抗借閱檢查器”變為“編譯器可以檢測到嗎?涼!”—Grzegorz Nosek

規模

當今的伺服器程式包含數千萬行程式碼,由成百上千的程式設計師進行處理,並且每天都會更新。Go 的設計和開發旨在提高在這種環境下的工作效率。Go 的設計考慮因素包括嚴格的依賴關係管理,隨著系統增長的軟體體系結構的適應性以及跨元件邊界的魯棒性。Rob Pike[17]

當你自己或以小組形式處理問題時,選擇簡單語言還是豐富語言是你的偏愛。但是隨著軟體變得越來越大,越來越複雜,以及團隊越來越大,這種差異真正開始顯現出來。對於大型應用程式和分散式系統,執行速度不如開發速度重要:像 Go 這樣的故意最小化的語言減少了新開發人員的啟動時間,並使他們更容易使用大型程式碼庫。

使用 Go,初級開發人員更容易提高工作效率,而中級開發人員更難引入脆弱的抽象,而抽象將導致問題。由於這些原因,Rust 在企業軟體開發方面不如 Go 引人注目。Loris Cro[18]

當涉及到大型軟體開發時,清晰勝於靈活。Go 的限制性實際上使它比 Rust 等更復雜、功能更強大的語言更適合企業和大型組織。

差異

儘管 Rust 和 Go 都是流行的,現代的,廣泛使用的語言,但從故意針對完全不同的用例的意義上來說,它們並不是真正的競爭對手。Go 的整個程式設計方法與 Rust 的方法完全不同,每種語言都適合某些人,同時又會激怒其他人。絕對很好,而且如果 Rust 和 Go 都以或多或少相同的方式或多或少地完成了相同的事情,那麼我們實際上就不需要兩種不同的語言。

那麼,通過發現它們採取截然不同的方法的問題,我們是否能夠了解 Rust 和 Go 的各自性質?讓我們找出答案。

垃圾回收

“進行垃圾收集或不進行垃圾收集”是沒有正確答案的問題之一。垃圾回收和自動記憶體管理通常使開發可靠,高效的程式變得快速簡便,對於某些人來說,這是必不可少的。但是其他人說,垃圾回收的效能開銷和停頓,使程式在執行時無法正常執行,並引入了無法接受的延遲。爭論不休。

Go 與 Rust 完全不同。儘管兩者都可以模糊地描述為系統語言或 C 語言的替代品,但它們具有不同的目標和應用,語言設計風格以及優先順序。垃圾收集確實是一個巨大的區別。在 Go 中使用 GC 可使該語言變得更加簡單和小巧。

在 Rust 中不使用 GC 可以使它真正更快(特別是如果你需要保證的等待時間,而不僅僅是高吞吐量),並啟用 Go 中無法實現的特性和程式設計模式(或者至少在不犧牲效能的情況下)。PingCAP[19]

更接近金屬(Close to the metal)

計算機程式設計的歷史一直是一個越來越複雜的抽象的故事,它使程式設計師能夠解決問題而不必擔心底層機器的實際工作原理。這使程式更易於編寫,並且可能更具移植性。但是對於許多程式而言,訪問硬體以及精確控制程式執行方式更為重要。Rust 的目標是讓程式設計師擁有更多的控制權,使其“更接近金屬”,但是 Go 提取了體系結構的詳細資訊,以使程式設計師更加接近問題。

兩種語言有不同的使用範圍。Golang 對於編寫微服務和典型的 “DevOps” 任務很有用,但它不是系統程式語言。對於併發性,安全性和/或效能很重要的任務,Rust 更強。但是它的學習曲線比 Go 更陡。Matthias Endler[20]

Go 發展更快

我在其他地方寫過,對於大多數程式而言,效能並不如可讀性重要[21]。但是,當效能確實很重要時,它真的很重要。Rust 進行了許多設計折衷,以實現最佳的執行速度。相比之下,Go 更加關注簡單性,並且願意為此犧牲一些(執行時)效能。但是 Go 的構建速度是無與倫比的,這對於大型程式碼庫而言非常重要。

Rust 比 Go 快。在上述基準測試中,Rust 速度更快,在某些情況下還快一個數量級。但是在選擇使用 Rust 編寫所有內容之前,請考慮一下 Go 在許多基準測試中並沒有落後很多,並且它仍然比 Java,C#,JavaScript,Python 等同類工具快得多。

如果你需要一流的效能,那麼你可以選擇這兩種語言中的任一種。如果你要構建一個處理高負載的 Web 服務,並且希望能夠在垂直和水平方向上進行伸縮,則兩種語言都將非常適合你。Andrew Lader[22]

正確性

另一方面,如果程式沒有正常執行,則可以任意快。大多數程式碼不是長期編寫的,但通常令人驚訝的是某些程式可以在生產環境中執行多長時間:在某些情況下需要數十年。在這種情況下,需要花一些額外的時間來開發程式,以確保程式正確,可靠並且將來不需要進行大量維護。

我的看法:明天將要釋出的程式碼選擇 Go,在未來五年內保持不變的程式碼選擇 Rust。—Grzegorz Nosek

儘管 Go 和 Rust 對於任何嚴肅的專案都是不錯的選擇,但最好使自己對每種語言及其特徵都儘可能瞭解。最終,其他人的想法無關緊要:只有你可以決定哪種對你和你的團隊是合適的。

如果你想加快開發速度,也許是因為你要編寫許多不同的服務,或者你有龐大的開發團隊,那麼 Go 是你選擇的語言。Go 為你提供了一流的併發性,並且不容許不安全的記憶體訪問(Rust 也不容忍),但不會強迫你管理每個最後的細節。Go 是快速而強大的工具,但是它避免了使開發人員陷入困境,而專注於簡單性和統一性。另一方面,如果需要擰緊塊效能,那麼 Rust 應該是你的選擇。Andrew Lader[23]

結論

我希望本文使你相信,Rust 和 Go 都值得你認真考慮。如果可能的話,你應該力求獲得至少兩種語言的某種程度的經驗,因為它們對你在任何技術職業中都是非常有用的,即使你喜歡將程式設計作為業餘愛好也是如此。如果你只有時間投入精力來學習一種語言,那麼請在將 Go 和 Rust 都用於各種大小不同的程式之前,不要做出最終決定。

而且,對程式語言的瞭解實際上只是成為一名成功的軟體工程師的一小部分。到目前為止,您將需要的最重要的技能是設計,工程,體系結構,溝通和協作。如果您擅長這些,那麼無論您選擇哪種語言,您都將是一名出色的軟體工程師。學習愉快!

原文連結:https://bitfieldconsulting.com/golang/rust-vs-go

原文作者:John Arundel

編譯:polarisxu