[Rust] PhantomData<T>

bluewhale·2021년 4월 14일
0

rust

목록 보기
2/3

본 글은 Phantom를 공부하며 작성한 글입니다. 오역 및 오류가 있을 수 있습니다. 이에 대해서는 댓글로 남겨주시면 감사하겠습니다.
https://stackoverflow.com/questions/41533508/what-is-the-phantomdata-actually-doing-in-the-implementation-of-vec/42720413

Rust standard library의 Vec<T> implementation을 공부하던 중, PhantomData<T> 데이터 타입을 접하게 되어 이와 관련된 글을 작성하게 되었습니다. PhantomData<T>는 역할을 알기 위해서는 먼저, Rust에서 Vec<T>가 어떻게 구현되어 있는지 알아볼 필요가 있습니다.

Vec<T>의 구조

Vec<T>는 내부적으로 대략 아래와 같은 구조를 가지고 있습니다. (실제로는 ptr과 _marker를 필드로 보유한 Unique<T>를 소유한 RawVec<T>을 가지고 있습니다. )

pub struct Vec<T> {
   ptr: *const T,
   cap: usize,
   len: usize,
   _marker: PhantomData<T>
}

각 필드를 살펴보면, ptr은 포인터, cap은 capacity, len은 길이를 나타냅니다. 이들은 직관적으로 배열을 구성하는 요소로 생각됩니다. 그렇다면, PhantomData<T>는 여기서 무슨 역할을 하는 것일까요?

How does Drop work?

PhantomDat<T>를 이해하기 위해서는 러스트의 Drop Trait이 어떻게 동작 하는지를 알 필요가 있습니다.

RFC1283 에 따르면, 일반적으로 포인터를 소유하는 것은 데이터를 빌려온(Borrowing) 것입니다. 따라서, 포인터를 소유한데이터 타입의 destructor가 호출될 때 해당 포인터가 가르키는 데이터 타입의 destructor는 호출되지 않습니다. 대부분의 경우, 이는 매우 합리적인 소유권 관리 방법으로 보입니다.

그러나, Vec<T>는 독특한 데이터 타입입니다.

Vec<T>는 내부적으로 포인터만을 가지고 있지만, 실질적으로 해당 데이터를 소유하고 있다고 봐도 무방합니다. 따라서, Vec<T>의 destructor가 호출될 때에는 T의 desturctor도 함께 호출되어야 합니다. PhantomData<T>는 이러한 정보를 컴파일러에게 전달하는 Marker Trait입니다.

Unqiue<T>

Rust의 standard library에서는 PhandomData<T>와 포인터(*const T)를 합친 Unique<T>를 제공합니다. Unique<T> 데이터 타입은 Vec<T>와 같은 자료구조 구현에 활용되고 있습니다. Unique<T>의 구조는 다음과 같습니다.

pub struct Unique<T: ?Sized> {
  ptr: *const T,
  _marker: PhantomData<T>,
}

impl<T: Sized> Unique<T> {
  /// Creates a new `Unique` that is dangling, but well-aligned
  /// This is useful for initializing types which lazily allocate, like `Vec`
  fn empty() -> Self {
      let ptr = std::mem::align_of::<T>() as *mut T;
      Self {
          ptr,
          _marker: PhantomData,
      }
  }
}
profile
안녕하세요

0개의 댓글