Rustコトハジメ

プログラミング言語Rustと競プロに関する情報をお届けします。

ファットポインタがほしいなら、明示的に型づけすること

impl<T> ops::Deref for Vec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        unsafe {
            let p = self.buf.ptr();
            assume(!p.is_null());
            slice::from_raw_parts(p, self.len)
        }
    }
}

Derefトレイトのおかげで、Rustは暗黙的に&Vec<T>から&[T]への変換を行ってくれます。

では質問ですが、以下のvp0の型はなんですか?

fn main() {
    let v: Vec<i32> = vec![1,2,3];
    let vp0 = &v; // Guess what type?
}

「Vecに&をつけたらスライスになる」と理解している人は、「&[i32]です」と答えたと思います。残念ながら答えは「&Vec<i32>」です。

確かめてみましょう。

fn main() {
    let v: Vec<i32> = vec![1,2,3]; // Owned pointer
    let vp0 = &v; //  Owned pointer's address
    let vp1: &Vec<i32> = &v; // same as above
    let vs: &[i32] = &v; // Fat pointer

    println!("{:p}={:p}", vp0, vp1);
}

この中で、vp0がvp1と等しい値ならば、vp0は&Vec<i32>であるといえそうですが、プリントした結果は

0x7ffc59a75bd0=0x7ffc59a75bd0

となり、vp0が&Vec<i32>であることがわかりました。

もちろん、関数の引数で&[i32]を要求している時などは&vとして与えるだけでコンパイルは通りますが、これはderef coercionによるものです。