為了搞懂Rust Pin在做什麼,耗費了很多精力,還真是有夠難懂的
About Self-Reference Type
有個資料結構, 其中有個指標指向結構自己或是結構中的某個欄位
例如
1 | struct Test { |
這裡的b_指向a_的地址, 同樣的事情在Rust寫成這樣
1 | struct Test { |
不看Rust的safe機制造成的不同,原理是相同的
現在的問題是,假設物件被移動了,指向結構中某部分的指標該怎麼辦
例如
1 | std::swap(test1, test2); |
先從我比較熟悉的C++來說好了
Solution1: Keep invariant
雖然達成目標的方法有很多,不過原則都是一樣:維持不變量就好了
1 | void swap(Test& lhs, Test& rhs) { |
很顯然,這個方法不適用於Rust
Solution2: Don’t move the object
所謂的Pin也就是這麼一回事,當物件停留在記憶體的某個位置之後,就不會再移動了,所以Self-Reference Type
的物件,在生命週期結束之前,所有的pointer和reference都會有效
在C++禁止的方法也不只一種,這是方法之一
1 | template <typename T> |
不過由於Rust講究Safety,所以訂了一堆規則
About Pin in Rust
在Rust中對Self-Reference Type的處理,我們要禁止的只有這件事
1 | pub fn swap<T>(x: &mut T, y: &mut T) { |
禁止Rust拿到&mut T
的Reference,&mut T
ˊ自然是不行,Box<T>
也做不到這件事,所以就是Pin<T>
登場的時候
Rust的Type分成兩類:
- Default Type:可以安全在Rust Move的類型
- Default Type都實作了auto
Unpin
trait,也就是什麼都不用做
- Default Type都實作了auto
- Self-Reference Type:也就是上面提到的部分
- 必須實作
!Unpin
的部分 - 使用
PhantomPinned
就可以了
- 必須實作
以下是個範例程式
1 | use std::pin::Pin; |
你把上面的PhantomPinned
註解掉,程式就能正常運作了
Pin還有很多細節,等我真的變成全職Rust工程師在研究吧