Newtype パターンにおける参照型の変換について。

基礎知識

Newtype パターン』では、既存の型をラップして新しい型を作る。これにより、汎用的な型の特殊化や、完成済の型の再編集が可能になる。なお、Rust で型 Old を型 New に単純にラップするには、struct New(Old); のように定義する。

参照型の変換

Newtype パターンでは、ラップ元の型の参照 &Old からラップ先の型の参照 &New への変換が欲しくなる場合がある。つまり、型システム的に区別はしているが、ラップ元とラップ先の内容は元々は同じである事を利用する。

実現方法

unsafe な機能 std::mem::transmute が必要になる。これでラップ元の型への参照をラップ先の型への参照として強引に扱う。そして、内容が同じでも最適化の都合などでメモリ構造が変わる可能性があるので、ラップ先の型に属性 #[repr(transparent)] を指定する事も忘れてはならない。

サンプル

以下では、from_ref 関数が &i32&Newtype に変換している。


fn main() {
    let base = 1;
    let newtype = Newtype::from_ref(&base);
    assert_eq!(newtype.value(), base);
}

#[repr(transparent)]
pub struct Newtype(i32);

impl Newtype {
    pub fn value(&self) -> i32 {
        self.0
    }

    pub fn from_ref(r: &i32) -> &Self {
        unsafe { std::mem::transmute(r) }
    }
}

クレート紹介

ref-cast

参照型のキャストのための専用クレート。参照から参照への変換を提供する RefCast トレイトとその自動実装により、unsafe コードの記述を肩代わりしてくれる。