トレイトの実装対象が参照型の場合について。

代表例は impl MyTrait for &MyType のようなコード。

注: コード内に参照型がなくても、型パラメタがあるとこのパターンになりうる。

特徴

参照の消費

self 引数により参照を消費する (参照の影響もなくなる)。

なお、この用法は後述のサンプルにて紹介する Iterator トレイトの count メソッドなどで見られる。このメソッドは要素数の確認のために、要素がつきるまでイテレータを走査する。そのため、値であれ参照であれ、以降はイテレータへのアクセスを提供するものは役に立たなくなるため、使用を禁止したほうがよい。

値からの呼出

メソッド呼出形式においては、参照型への実装のみで値型も自動サポートされる。

これは自動参照があるためで、&self を使った場合の自動逆参照と似ている。

なお、必要になる事は少なそうだが、参照版と値版とで実装を二つ用意してもよい。

用例

用例 1

参照型版

以下では、末尾の実装の & の箇所が重要。


fn main() {
    let r = &MyType {};
    r.with_self_value();
}

trait MyTrait {
    fn with_self_value(self) where Self: Sized {}
}

struct MyType {}

impl MyTrait for &MyType {}

用例 2

型パラメタ版

以下では、型パラメタ T が参照型も含んでいる。


fn main() {
    let r = &MyType {};
    r.with_self_value();
}

trait MyTrait {
    fn with_self_value(self) where Self: Sized {}
}

struct MyType {}

impl<T> MyTrait for T {}

用例 3

身近な例

Iterator の一部メソッドなどに利用例がある。

関連する宣言

以下は Iteratorcount メソッド。


fn count(self) -> usize where Self: Sized

以下は Iterator の参照に対する実装。


impl<I: Iterator + ?Sized> Iterator for &mut I

呼出側のコード

そのため、以下のようなコードが可能。


fn main() {
    let vec = vec![1, 2, 3];
    let iter = &mut vec.iter();
    assert_eq!(iter.count(), 3);
}