スマートポインターの独自実装(@Rust)

Box<T>のようなスマートポインターの独自実装がRustドキュメントの中に出てきます。Box<T>は一番基本的なスマートポインターで他にもいくつか存在しますが、

https://doc.rust-jp.rs/book-ja/ch15-02-deref.html

もともとスマートポインターはRust固有ではなくC++でもありますが、定義は『通常のポインタのように振る舞うだけでなく、追加のメタデータと能力があるデータ構造』とありますが、追加のメタデータと能力とは以下のサンプルコードで示される参照外しは一例かと思います。もともとC++におけるスマートポインターも目的とするところはほぼ同じ。

以下のコードはリンクからのコードですが、独自のMyBox(Box相当)でBoxのメソッドの一つであるnew()を実装すれば、引数の値をヒープエリアに割り当ててくれます。ただし、DerefをMyBoxメソッドに対して実装しないとせっかくMyBoxで割り当てたメモリエリアの参照ができないので、以下のコードはコンパイルできません。

hello関数と呼出の例は、もしMyBoxにDerefが実装されていないと呼び出しが煩雑になるよという例を示すためで、もしDeref実装がないと以下のような読みづらいコードを書かないといけないようです。

hello(&m); –> hello(&(*m)[..]);

これは、

https://qiita.com/moyamoyac/items/5aea471d6676625dcd62

で記述されているように、以下の三段階の変換が組み込まれたコードなのでぱっと見分かりづらい。

mMyBox<String>
*mString
&(*m)[..]&str

 

use std::ops::Deref;

struct MyBox<T>(T);

impl MyBox<T> {      // original smart pointer
    fn new(x: T) -> MyBox {
        MyBox(x)
    }
}

impl Deref for MyBox {    // deref coercion
    type Target = T;    // to define return value type T for the Deref "Target"
                        // in the DeRef trait : fn deref(&self) -> &Self::Target;

    fn deref(&self) -> &T {
        &self.0
    }
}

fn hello(name: &str) {          // "&" is needed to get a known size of the argument at compile-time
    println!("Hello, {}!", name);
}

fn main() {
    let x = 5;
    let y = MyBox::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);  // to success compile, Deref definition should be defined

    println!("x = {}, y = {}", x, *y);

    let m = MyBox::new(String::from("Rust"));
    hello(&m);
}

 

admin

カテゴリーRust