Rust之PhantomData

PhantomData<T>是一个零大小类型的标记结构体。

作用:

  1. 并不使用的类型;
  2. 型变;
  3. 标记拥有关系;
  4. 自动trait实现(send/sync);

并不使用的类型

生命周期

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

然而,因为'a在结构体中未使用,所以它是无界的。在结构定义中禁止无限生命周期和类型。

修改如下:

use std::marker;

struct Iter<'a, T: 'a> {
    ptr: *const T,
    end: *const T,
    _marker: marker::PhantomData<&'a T>,
}

类型

pub struct RetryableSendCh<T, C: Sender<T>> {
    ch: C,
    name: &'static str,
    marker: PhantomData<T>,
}

标记拥有关系

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

原生指针不具有所有权语义,drop检查器将认为Vec<T>不具有类型T的任何值。这将反过来使得它不需要担心Vec在其析构函数中丢弃任何T。但是有可能T被提前释放。为了drop检查器认为vec一定拥有了T的数据,修改如下:

use std::marker;

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

型变

  • 不变

如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变

  • 逆变

可以由其基类替换。

  • 协变

可以由其派生类型替换。

PhantomData模式表

这是一张PhantomData可以使用的所有方法的表格:

Phantom type 'a T
PhantomData<T> - variant (with drop check)
PhantomData<&'a T> variant variant
PhantomData<&'a mut T> variant invariant
PhantomData<*const T> - variant
PhantomData<*mut T> - invariant
PhantomData<fn(T)> - contravariant (*)
PhantomData<fn() -> T> - variant
PhantomData<fn(T) -> T> - invariant
PhantomData<Cell<&'a ()>> invariant -

(*)如果逆变被废除,这将是不变的。

推荐阅读更多精彩内容

  • Java为什么引入泛型 众所周知,Java 5才最大的亮点就是引入泛型,那么Java引入泛型的目的是什么?这就需要...
    大棋17阅读 695评论 0 3
  • 原文:Fearless Concurrency with Rust by Aaron Turon Apr 10,...
    猿基地阅读 10,685评论 0 69
  • “泛型”这个术语的意思是:"适用于许多许多的类型”。如何做到这一点呢,正是通过解耦类或方法与所使用的类型之间的约束...
    王侦阅读 676评论 0 0
  • 20171107星期二 今天休班了,一个多月没回老家了,想家了。到家十一点了,老爸忙着做饭,我闲着没事干,心想孩子...
    子涵的妈妈阅读 63评论 0 0
  • 许多没有明师指导的修炼者,往往认为筑基阶段一定是下丹田发热后逆上三关通任督二脉,然后通大周天这样一个按部就班的过程...
    明树阅读 219评论 0 0