Rust的Vector vs. Golang的Slice比較

banq發表於2022-06-23

我的網站是用Go編寫的,當程式啟動時,它會讀取 "blog/"資料夾的內容,並儲存所有文字檔案的路徑,解析所有內容,將每個檔案轉換為Post結構struct,並追加到Post切片slice中。

我最近開始學習Rust,在閱讀這本書時,我注意到切片的工作方式與Go不同,而是使用Vectors。
不明白這到底是為什麼?

Go的slice同時包涵了Rust的Vec和Rust的 "slice"
在Go中,[]T涵蓋了 "可擴充套件的儲存 "和 "可在恆定時間內建立的對另一個slice的引用"。
在Rust中,這些情況被分割開來。如果你有一個Vec,那麼你知道你總是可以新增到它。你對它有所有權。如果你有一個&[T](甚至是一個&mut[T]),那麼你所知道的就是它是一個長度和一個指向某個連續的記憶體區域的指標。你無法擴充套件它。
同樣地,如果你有一個Vec,你不能建立另一個Vec來指向第一個Vec。它必須是一個複製副本。

為什麼Go和Rust使用相同的詞"slice",但概念不同?
一個潛在的更有趣的問題是,"為什麼Rust將Go的slice概念分成兩個不同的型別?"
只有一種型別在概念上不是更簡單嗎?
這真的涉及到語言設計,但我認為這真的可以歸結為兩件事:

  1. Rust有所有權,沒有垃圾收集器。
  2. Go則沒有所有權的概念。

在Go中給定一個[]T,你不知道你是否擁有它。你不知道---至少從型別系統來看---你是否被允許對它進行變異而不產生UB。
在Rust中,這兩個概念幾乎必須在所有權的基礎上被分割開來。

然而,你可以通過引用計數在Rust中實現類似Go的slice。(這有點像位元組箱所做的,只是它只適用於Vec<u8>,而不是Vec<T>。) 問題是,引用計數會增加開銷,而給Vec這樣的核心基元增加開銷並不是好事。
在Go中,這種開銷是完全沒有問題的,因為它是一種GC語言,而且GC的使用是無處不在的。它首先是內建於使用該語言的成本中的。

所以,就像我說的,Rust在這裡要複雜一些,因為它的語言設計的目標所帶來的限制。

好了,又上升了一個層次,回到了問題上:為什麼對同一個概念使用不同的名字?
C語言的void和Haskell的void是兩個完全不同的東西。有時 "垃圾收集 "包括引用計數,有時不包括。"正規表示式 "實際上可能意味著 "看起來像正規表示式的東西,但實際上可以描述比正則語言更多的東西。"

毫不含糊和精確是有代價的。語境上下文就是一切。
你不能假設在一種程式語言中用來描述一個特定概念的詞在其他每一種程式語言中都會以同樣的方式使用。
事實上,通常的情況是,這些概念是如此的相似和重疊,以至於很難不假設這樣的事情,也許就像Go和Rust中的 "slice "一樣。但是,一旦你熟悉了不同的程式語言可能用微妙的不同的詞來描述同一個概念的想法,我想你至少會對它不那麼吃驚了。

相關文章