@ledsun blog

Hのキーがhellで、Sのキーがslaveだ、と彼は思った。そしてYのキーがyouだ。

rustを味見する 6

1.6.1 Rustの目標:安全性

の15ページのサンプルプログラムです。

#[derive(Debug)]
enum Cereal {
    Barely, Millet, Rice, Rye, Spalt, Wheat
}

fn main() {
    let mut grains: Vec<Cereal> = vec![];
    grains.push(Cereal::Barely);
    drop(grains);
    println!("{:?}", grains);
}

コンパイルエラーがでます。

f:id:ledsun:20220109100715p:plain
コンパイルエラー

「VecにCopyが実装されていないので、moveが起きた」と読めます。 意味不明です。 さらによくわからないのがdropしたときにmoveが起きたと言う説明です。 dropは削除であってmoveではないように思えます。

Drop trait

dropは何者なのでしょうか? drop(grains)とあるので、グローバルに存在する関数に見えます。 https://doc.rust-lang.org/reference/special-types-and-traits.html?highlight=Drop#drop にはtraitとあるので、Vec structのメソッドなのかもしれません。 https://doc.rust-lang.org/std/vec/struct.Vec.html#impl-Drop をみるとやはりそのようです。

Executes the destructor for this type.

とあるので、デストラクタの実行。 つまりgrains変数に代入されているVec<Cereal>インスタンスを破棄しているようです。

ということはCopy traitが実装されている場合は、Vec<Cereal>インスタンスを破棄した後も、grains変数を参照している限りはコピーされたインスタンスが生き残るのでしょうか?

ぶら下がりポインタ

この説明は、コンパイラが「ぶら下がりポインタ」を検出する例です。 「ぶら下がりポインタ」とは何でしょうか? ダングリングポインタとは|dangling pointerの危険性と回避 | MaryCoreによると

有効だったメモリ領域が解放処理などによって無効化されたにもかかわらず、そのメモリ領域を参照し続けているポインタのことを、ダングリングポインタと呼ぶ。

まさに、drop(grains)したあとに、grainsに参照することのようです。 このサンプルプログラムは「ぶら下がりポインタ」の問題を素直に実装した物のようです。

rustでは「ぶら下がりポインタ」を検出するために、moveとかcopyとかその辺の仕組みを使っているようです。 学習を進めていけば、そのうち理解できるのでしょう。