Go vs Rust? Choose Go.

Matthias Endler

Go vs Rust?選擇 Go。

透過 Gopherize.me 設計的 Gopher。由 Freepik 設計的齒輪。
來源:Gopher 由 Gopherize.me 設計。齒輪由 Freepik 設計。

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

為了提供更平衡的優缺點觀點,我建議改讀這篇關於 Go vs Rust 的比較文章,這是我與 Shuttle 🚀 合作撰寫的:

Rust vs Go:動手實作比較

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

Go:實用、務實、簡樸

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

我不認為 Go 是個優雅的語言。它最大的特色不是 簡潔 而是 易用性。Go 甚至不是一種 systems programming 語言。雖然它非常適合用來撰寫 microservices(微服務)以及後端基礎架構的相關工具,但我不會想用它來撰寫核心或 memory allocator(記憶體配置器)。

但使用 Go,你可以 快速完成工作——很快。
Go 是我用過生產力最高的語言之一。它的信條是:今天就解決實際問題。

Rust 強大的保證是有代價的

Rust 隨時間的學習曲線,崎嶇顛簸的旅程。
Rust 隨時間的學習曲線,崎嶇顛簸的旅程。

相比之下,Rust 是 困難的。我花了好幾個月才變得稍微有生產力。你需要投入大量的時間才能看到任何好處。Rust 已經是一個強大的語言,而且每天都在變得更強大。在我看來,它更像是一種 務實的 Haskell,而不是 更安全的 C

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

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

  • 針對 Null 指標、race conditions(競態條件)以及各種低階威脅的安全性。
  • 可預測的執行時期行為(zero cost abstractions(零成本抽象)且沒有 garbage collector(垃圾回收機制))。
  • 對硬體(幾乎)完全的掌控(memory layout(記憶體佈局)、processor features(處理器功能))。
  • 與其他語言無縫的互通性。

如果你並非 需要這些特性的任何一項,Rust 對你的下一個專案來說可能是個不佳的選擇。這是因為這些保證是有代價的:上手時間。你需要改掉壞習慣並學習新概念。剛開始時,你很可能會不斷地 與 borrow checker(借用檢查器)對抗

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

假設你想檢查一個數字是否為 質數。最簡單的方法是檢查這個數能否被任何較小的自然數整除(沒有餘數)。如果不行,我們就找到了一個質數!這種方法稱為 試除法

以下是用 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 更具函數式風格。你也可以使用為 Range 實作的 any 方法來重寫上述程式碼。

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 指標、沒有 data races(資料競爭)……
  • 細緻的系統控制
  • 驚人的執行時期速度(可與 C/C++ 相比)
  • Zero-cost abstractions
  • 優秀且開放的社群
  • 透過 cargo 實現簡潔的套件管理
  • 以 traits(特徵) 形式支援 Generics(泛型)
  • C interop 和 FFI(外部函式介面)

結論

99% 的情況下,Go 已經「夠用」了,而那 1% 不夠用的時候,你自然會知道。到時候再來看看 Rust,因為這兩個語言互補得相當好。如果你對 實作導向的 Rust 諮詢服務 有興趣,請從我的行事曆中挑選一個時間,我們可以聊聊我能如何提供協助。

歸根究柢,Rust 和 Go 並非真正的競爭對手

原文由 Matthias Endler 發布

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