Progrust Library.

// dictionary

自動参照・自動参照外し.

自動参照・自動参照外し(automatic referencing and dereferencing)とは、値.メソッド名()というメソッド呼び出しの際に、コンパイラがレシーバ(ドットの左側の値)をselfの型に合わせて調整してくれる仕組みです。self&self&mut selfならレシーバに&&mutを補って借用し(自動参照)、レシーバがBox越しの値などであれば*を補って参照外しします(自動参照外し)。

そのためRustにはC/C++の->演算子に相当するものがなく、レシーバが値でも参照でもBox越しでも同じドット記法で書けます。レシーバの借用が暗黙になることで、所有権を扱うコードを簡潔に書けるようになっています。

struct Cart {
    prices: Vec<u32>, // 各商品の価格(円)
}

impl Cart {
    fn add(&mut self, price: u32) {
        self.prices.push(price);
    }

    fn total(&self) -> u32 {
        self.prices.iter().sum()
    }
}

fn main() {
    let mut cart = Cart { prices: Vec::new() };

    cart.add(300); // 自動参照: (&mut cart).add(300) と同じ
    cart.add(150);
    println!("合計: {}円", cart.total()); // 自動参照: (&cart).total() と同じ

    let boxed = Box::new(cart);
    println!("箱の中の合計: {}円", boxed.total()); // 自動参照外し+自動参照: (&*boxed).total() と同じ
}
Playgroundで開く

レシーバ型の探索手順

コンパイラは、呼び出すメソッドを次の手順で決定します。

  1. レシーバの型を出発点に、参照外しできる限り繰り返して候補型を並べます(Deref実装をたどります)。最後に配列型からスライスへの非サイズ化変換(unsized coercion)を試し、成功すればその型も加えます
  2. 各候補型Uの直後に&U&mut Uを挿入します
  3. 候補型の並び順に、その型の固有メソッド→その型が実装する可視なトレイトのメソッド、の順で探し、最初に見つかったものを呼びます
候補型の並び(Box<[i32; 2]>の場合)
候補型 由来
1〜3 Box<[i32; 2]> / &Box<[i32; 2]> / &mut Box<[i32; 2]> レシーバ自身と借用版
4〜6 [i32; 2] / &[i32; 2] / &mut [i32; 2] 参照外し(Deref
7〜9 [i32] / &[i32] / &mut [i32] 非サイズ化変換

Box<[i32; 2]>の値に対してスライスのメソッドがそのまま呼べるのは、この並びの後半までたどられるためです。

補足

可変性・ライフタイムは探索時に考慮されない

この探索は、レシーバの可変性やライフタイム、メソッドがunsafeかどうかを考慮しません。メソッドが決まった後にそれらの理由で呼び出せないと分かった場合は、その時点でコンパイルエラーになります。

また、同じ候補型で複数のメソッドが該当してしまう場合も曖昧さのエラーになります。この場合はTrait::method(&value)のような完全な関数呼び出し構文で呼び分けます。

フィールドアクセスでは自動参照外しのみが働く

x.fieldのようなフィールドアクセスでも、Deref(可変な場所ならDerefMut)を実装した型であれば、アクセス可能になるまで必要な回数だけ自動で参照外しが行われます。ただしこちらで働くのは参照外しだけで、メソッド呼び出しのような自動参照は行われません。

この辞書が使われているページ

backlinks 5

  1. 辞書メソッド
  2. 辞書関連関数
  3. 辞書参照
  4. 辞書参照外し
  5. 動かして学ぶRustプログラミング問題集 › 第10章 メソッドと関連関数