在 TiKV 的一次提交里面,同事用了一個(gè) PhantomData
的 marker恐锦,當(dāng)時(shí)我就覺(jué)得很奇怪往果,因?yàn)閺膩?lái)沒(méi)用過(guò),這是什么東西一铅,做什么用的陕贮?瀏覽了一下 doc,發(fā)現(xiàn)主要是干這幾件事情的潘飘。
Unused lifetime
在一些 Unsafe 的代碼里面肮之,我們很有可能有一個(gè)沒(méi)有用的 lifetime 參數(shù),譬如一個(gè) Slice卜录,我們可能有兩個(gè) start 和 end 的 *const T
指針:
struct Slice<'a, T> {
start: *const T,
end: *const T,
}
Slice 的 lifetime 是 'a
戈擒,也就是不能超過(guò) 'a
的生存周期,但實(shí)際 Slice 上面并沒(méi)有表現(xiàn)出來(lái)艰毒,因?yàn)闆](méi)有任何地方使用了這個(gè) 'a
筐高,為了解決這個(gè)問(wèn)題,我們就可以使用 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 來(lái)說(shuō)冰单,也有可能自己的 field 并沒(méi)有使用 Type Parameter,為了解決這個(gè)問(wèn)題灸促,我們也可以使用 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 了 類(lèi)型 T
的實(shí)際數(shù)據(jù)浴栽,這就說(shuō)是當(dāng) struct 被 drop 的時(shí)候荒叼,一些類(lèi)型 T
的實(shí)例也會(huì)被 drop 掉。所以如果我們的 struct 并沒(méi)有實(shí)際的 own 類(lèi)型 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 類(lèi)型 T
的任何數(shù)據(jù)萝玷,也就是說(shuō)當(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ì)于這門(mén)語(yǔ)言來(lái)說(shuō),讓我學(xué)習(xí)的地方還有很多挎春。