在 TiKV 的一次提交里面,同事用了一個(gè) PhantomData 的 marker,當(dāng)時(shí)我就覺得很奇怪,因?yàn)閺膩頉]用過,這是什么東西,做什么用的?瀏覽了一下 doc,發(fā)現(xiàn)主要是干這幾件事情的。
Unused lifetime
在一些 Unsafe 的代碼里面,我們很有可能有一個(gè)沒有用的 lifetime 參數(shù),譬如一個(gè) Slice,我們可能有兩個(gè) start 和 end 的 *const T 指針:
struct Slice<'a, T> {
start: *const T,
end: *const T,
}
Slice 的 lifetime 是 'a,也就是不能超過 'a 的生存周期,但實(shí)際 Slice 上面并沒有表現(xiàn)出來,因?yàn)闆]有任何地方使用了這個(gè) 'a,為了解決這個(gè)問題,我們就可以使用 PhantomData:
use std::marker::PhantomData;
struct Slice<'a, T: 'a> {
start: *const T,
end: *const T,
phantom: PhantomData<&'a T>,
}
上面,我們使用了一個(gè) PhantomData,使用了 lifetime 'a,這樣就明確表示 Slice 的生存周期是 'a 了。
Unused Type
對(duì)于一些 generic struct 來說,也有可能自己的 field 并沒有使用 Type Parameter,為了解決這個(gè)問題,我們也可以使用 PhantomData。在 TiKV 的代碼里面,我們就是這么處理的:
pub struct RetryableSendCh<T, C: Sender<T>> {
ch: C,
name: &'static str,
marker: PhantomData<T>,
}
Ownership and Drop check
在 struct 里面加入 PhantomData<T> 也表明我們 own 了 類型 T 的實(shí)際數(shù)據(jù),這就說是當(dāng) struct 被 drop 的時(shí)候,一些類型 T 的實(shí)例也會(huì)被 drop 掉。所以如果我們的 struct 并沒有實(shí)際的 own 類型 T 的數(shù)據(jù),我們需要使用 PhantomData<&'a T> 或者 PhantomData<*const T>。
譬如我們定義一個(gè) Vec:
struct Vec<T> {
data: *const T, // *const for variance!
len: usize,
cap: usize,
}
在上面的例子中,drop 并不會(huì)認(rèn)為 Vec own 類型 T 的任何數(shù)據(jù),也就是說當(dāng) drop 這個(gè) vec 的時(shí)候,相關(guān)的 T 數(shù)據(jù)并不會(huì)被 drop 掉。為了讓 drop checker 認(rèn)為 vec 一定 own 了 T 的數(shù)據(jù),我們可以使用:
use std::marker;
struct Vec<T> {
data: *const T, // *const for covariance!
len: usize,
cap: usize,
_marker: marker::PhantomData<T>,
}
小結(jié)
Rust 的 PhantomData 對(duì)我是一個(gè)全新的特性,雖然它已經(jīng)存在很久了。對(duì)于這門語言來說,讓我學(xué)習(xí)的地方還有很多。