Phantom Data

在 TiKV 的一次提交里面,同事用了一个 PhantomData 的 marker,当时我就觉得很奇怪,因为从来没用过,这是什么东西,做什么用的?浏览了一下 doc,发现主要是干这几件事情的。

Unused lifetime

在一些 Unsafe 的代码里面,我们很有可能有一个没有用的 lifetime 参数,譬如一个 Slice,我们可能有两个 start 和 end 的 *const T 指针:

struct Slice<'a, T> {
    start: *const T,
    end: *const T,
}

Slice 的 lifetime 是 'a,也就是不能超过 'a 的生存周期,但实际 Slice 上面并没有表现出来,因为没有任何地方使用了这个 'a,为了解决这个问题,我们就可以使用 PhantomData:

use std::marker::PhantomData;

struct Slice<'a, T: 'a> {
    start: *const T,
    end: *const T,
    phantom: PhantomData<&'a T>,
}

上面,我们使用了一个 PhantomData,使用了 lifetime 'a,这样就明确表示 Slice 的生存周期是 'a 了。

Unused Type

对于一些 generic struct 来说,也有可能自己的 field 并没有使用 Type Parameter,为了解决这个问题,我们也可以使用 PhantomData。在 TiKV 的代码里面,我们就是这么处理的:

pub struct RetryableSendCh> {
    ch: C,
    name: &'static str,

    marker: PhantomData,
}

Ownership and Drop check

在 struct 里面加入 PhantomData 也表明我们 own 了 类型 T 的实际数据,这就说是当 struct 被 drop 的时候,一些类型 T 的实例也会被 drop 掉。所以如果我们的 struct 并没有实际的 own 类型 T 的数据,我们需要使用 PhantomData<&'a T> 或者 PhantomData<*const T>

譬如我们定义一个 Vec:

struct Vec {
    data: *const T, // *const for variance!
    len: usize,
    cap: usize,
}

在上面的例子中,drop 并不会认为 Vec own 类型 T 的任何数据,也就是说当 drop 这个 vec 的时候,相关的 T 数据并不会被 drop 掉。为了让 drop checker 认为 vec 一定 own 了 T 的数据,我们可以使用:

use std::marker;

struct Vec {
    data: *const T, // *const for covariance!
    len: usize,
    cap: usize,
    _marker: marker::PhantomData,
}

小结

Rust 的 PhantomData 对我是一个全新的特性,虽然它已经存在很久了。对于这门语言来说,让我学习的地方还有很多。

你可能感兴趣的:(Phantom Data)