Go vs Rust? Choose Go.

Matthias Endler

Go vs Rust?選 Go。

原文由 Matthias Endler 發布,訂閱此部落格

Gopher 使用 Gopherize.me 設計,齒輪由 Freepik 設計。
來源:Gopher 使用 Gopherize.me 設計,齒輪由 Freepik 設計。

這篇文章是很久以前寫的。這段期間,我對某些觀點的看法已經有所改變。

為了更平衡地呈現優缺點,我建議改看這篇我與 Shuttle 合作撰寫的 Go 與 Rust 比較文 🚀

Rust vs Go: A Hands-On Comparison

「該選 Rust 還是 Go?」是我經常被問到的問題。這兩個語言看起來在爭奪同一群使用者,而且兩者似乎都是系統程式語言,所以一定有個明顯的贏家,對吧?

Go:務實、講求實用、樸實無華

Golang 隨時間變化的學習曲線,一條直線。
Golang 隨時間變化的學習曲線,一條直線。

我不覺得 Go 是個優雅的語言。它最大的特色不是簡潔 易學。Go 甚至算不上是系統程式語言。雖然它很適合用來撰寫微服務和後端基礎架構的周邊工具,但我不會想用它來寫核心或記憶體配置器。

但用 Go,你可以快速把事情完成
Go 是我用過生產力最高的語言之一。它的信條就是:今天就解決真正的問題。

Rust 強大的保證是有代價的

Rust 隨時間變化的學習曲線,顛簸起伏的過程。
Rust 隨時間變化的學習曲線,顛簸起伏的過程。

相比之下,Rust 是困難的。我花了好幾個月才達到有點生產力的程度。你需要投入相當多的時間才能看到回報。Rust 已經是一個強大的語言,而且每天都在變得更強大。對我來說,它感覺上更像是務實版的 Haskell,而不是更安全的 C

別誤會:我熱愛 Rust,它也讓我成為更好的程式設計師。它絕對是個值得學習的好語言。真正的問題在於,它是不是你下一個大型專案的正確選擇。

重點是:如果你選擇 Rust,通常是因為你需要這個語言所提供的那些保證:

  • 能防範 Null 指標、競爭條件與各種低階威脅的安全性。
  • 可預測的執行期行為(零成本抽象與沒有垃圾回收機制)。
  • (幾乎)完全掌控硬體(記憶體配置、處理器特性)。
  • 與其他語言無縫互通。

如果你不需要這些特性中的任何一項,Rust 對你的下一個專案來說可能是個不好的選擇。因為這些保證是有代價的:上手時間。你得戒掉壞習慣、學習新觀念。剛開始時,你很有可能會一直跟借用檢查器奮戰

案例研究:用試除法判斷質數

假設你想檢查一個數字是不是質數。最簡單的方法就是檢查能不能被任何更小的自然數整除(沒有餘數)。如果都不行,就代表找到質數了!這種方法就叫做試除法

以下是在 Golang 中實作的方法(感謝 Rosetta Code):

func IsPrime(n int) bool {
	if n < 0 {
		n = -n
	}
	switch {
	case n < 2:
		return false
	default:
		for i := 2; i < n; i++ {
			if n%i == 0 {
				return false
			}
		}
	}
	return true
}

而同樣的邏輯用 Rust 寫是這樣:

pub fn is_prime(n: u64) -> bool {
    match n {
        0...1 => false,
        _ => {
            for d in 2..n {
                if n % d == 0 {
                    return false;
                }
            }
            true
        }
    }
}

乍看之下,兩種解法看起來很相似。但仔細看,就能發現一些差異。

  • 在 Go 中,我們使用簡單的 switch-case 陳述式。在 Rust 中,我們使用 match 陳述式,它強大得多。
  • 在 Go 中,我們用簡單的 for 迴圈來遍歷 2 到 n 的數字。在 Rust 中,我們使用範圍表達式(2..n)。
  • 在 Go 中,我們用了兩個 return 陳述式,在 Rust 中則是只有一個 return 表達式。一般來說,Rust 中的大多數東西都是表達式,可以被回傳並指派給變數。想了解更多關於表達式的內容,請看這裡

在許多方面,Rust 比 Golang 更具函數式風格。你可以用 any 方法重寫上面的程式碼,這個方法是為 Range 實作的。

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

一開始可能會覺得有點陌生,但過一陣子就會習以為常了。

當然,這只是一個快速的範例。我建議你到 Rosetta Code 上瀏覽一些程式碼,對這兩個語言會有更具體的感受。

案例研究:在文字檔中尋找重複的單字

如果你是比較偏視覺型的人,這裡有一支影片,是我用 Go 和 Rust 寫一個簡單的並行程式來比較兩種語言:

我喜歡 Go 的一些地方

  • 編譯速度快
  • 務實的問題解決導向
  • 針對典型 DevOps 任務的完善生態系
  • 功能齊全的標準函式庫
  • IDE 支援
  • 簡單的錯誤處理
  • 吉祥物 😉

我喜歡 Rust 的一些地方

  • 安全性:沒有 null 指標、沒有資料競爭……
  • 細緻的系統控制
  • 驚人的執行速度(可與 C/C++ 媲美)
  • 零成本抽象
  • 很棒、開放的社群
  • 用 cargo 進行簡單的套件管理
  • 以 trait 形式支援泛型
  • C 語言互通與 FFI

結論

99% 的情況下,Go 已經「夠好了」,而剩下那 1% 不夠好的時候,你自然會知道。到那時再來看看 Rust,因為這兩個語言其實相輔相成。如果你對實作導向的 Rust 諮詢有興趣,從我的行事曆上挑個時間,我們可以聊聊我能如何幫忙。

說到底,Rust 和 Go 其實並非競爭對手

本文章由 muse-spark-1.2-contributor 進行翻譯

留言