Rust 中的 ptr::Shared 使用問題?

Rust 的官方 linkedlist 實現,為什麼使用 Option&&>&> 而不是 Option&&>&>&> 表示前後指針?


1. 其它答案已經說了,性能原因,寫鏈表為什麼要用引用計數?這個開銷毫無意義。

2. 可以用裸指針來實現,但是如果我們把裸指針包起來設計一個 Shared 類型,再在它基礎上實現LinkedList,主要是防止重複代碼,這個 Shared 類型不止在 LinkedList 中有用,其它很多數據結構都可以用。

那麼就需要繼續說一下這個 Shared 類型究竟在裸指針之上封裝了一些什麼東西:

a) 滿足 drop checker. 看源碼及注釋可知,它裡面有個成員是 PhantomData&

b) 默認非空指針。它把裸指針用 NonZero 包了一層,只要初始化的時候自己注意一下別用空指針,後面使用的時候可以不必每次檢查是否為空。

c) impl Send/Sync.

這個 Shared 類型在標準庫中實際上是跟 Unique 類型對應的一個類型。如果用戶需要使用裸指針,在大部分情況下,應該建議用 Unique/Shared 來代替,它們執行期開銷和裸指針一樣,但是在裸指針基礎上增加了額外的語義信息。這些信息在實現不同數據結構的時候是都要寫的重複代碼。其中,還有最重要的一條語義在上面沒有說:

Shared 指針是 alias-able 的,而 Unique 指針是 noalias 的。就像C語言裡面的指針加不加 restrict 關鍵字修飾的區別。目前這一點暫時還沒實現,這個信息並沒有傳遞給 LLVM 做優化,但是使用者應該牢牢記住這條語義,這是它們倆的最重要的區別。

這就是為什麼 LinkedList 必須使用 Shared 而不能使用 Unique 的原因。鏈表中的 Node 不僅有前面一個元素指向它,還有後面一個元素指向它。這是顯然存在 alias 的場景。


根據文檔 core::ptr::Shared - Rust 和源碼 ptr.rs.html -- source

Shared 就是保證非 null 的 raw pointer,對比 raw pointer 的好處是不用檢查 null,然後有類型信息。沒有任何開銷。

鏈表前驅和後繼不會被別的鏈表共享,否則就是 Graph 了,所以不可能用 Rc。(Rc 也不能用於 Graph,因為循環引用……)

從數據類型來說,和別的 collection 一樣,一個鏈表作為整體管理可變性。利用編譯器的特性就可以保證可變性了,也不需要用 RefCell,RefCell 內部有鎖,以檢測重複的引用,雖然開銷不大,但是在這種場合用也是完全沒有必要的。

缺點是因為是 raw pointer ,Rust 自身的安全系統完全沒有用,這類數據結構編程起來小心翼翼的程度回到了 C(實際上就當成是C……)。

不過因為是 std,所以沒問題。

實際上編寫複雜數據結構很難避免 raw pointer,而大多數數據結構作為一個整體設計,會暴露出安全的介面,只要編碼正確,不安全性也只會被局限在數據結構內部。

另外,如果對 Rust 實現 Graph 感興趣 Modeling graphs in Rust using vector indices


比起Shared&,Rc&&>要貴多啦


推薦閱讀:

Rust 語言現在什麼情況,為什麼知乎上不怎麼討論Rust語言了呢?
如何看待12306同一個人,同一次列車不能分段買兩張票?
可以實現在"文件A"中存儲其md5值嗎?
有什麼有趣的 Python 模塊值得推薦?
編程時候這麼多的函數方法之類的是怎麼記下來的??

TAG:編程 | Rust編程語言 |