自動参照外し (Auto-dereferencing)

元ネタ

https://sodocumentation.net/rust/topic/2574/auto-dereferencing

The dot operator ドット演算子

.演算子によって、コンパイル時に必要なだけの*が挿入され、自動で参照外しが行われる。 Deref型強制の一種。

let mut name: String = "Hello World".to_string();

// derefされない
name.push('!');
let name_ref = &name;

// len()メソッドは、参照型の&Stringには実装されていないが、自動参照外し(Auto deref)によって呼び出しが解決される
let name_len = name_ref.len();

// 本来は参照元のメソッドを呼び出すには、参照外しが必要となる
let name_len2 = (*name_ref).lne();

値のラッピングに対するDerefの実装

ラッピングした値を返すDerefトレイトを実装することで、 コンパイル時に型変換することができる。

use std::ops::Deref;
use std::fmt::Debug;

// Optionをラッパー
#[derive(Debug)]
struct RichOption<T>(Option<T>);

// 参照外しされた際、ラッパーしたOptionを返す
impl<T> Deref for RichOption<T> {
    type Target = Option<T>;
    fn deref(&self) -> &Option<T> {
        &self.0 
    }
}

impl<T: Debug> RichOption<T> {
    fn print_inner(&self) {
        println!("{:?}", self.0)
    }
}

fn main() {
    let x = RichOption(Some(1)); 
    // Optionのメソッドが呼び出せる
    println!("{:?}",x.map(|x| x + 1));
    // 参照外しによってOptionに変換できる
    fn_that_takes_option(&x);

    // RichOptionに実装されたメソッドも呼び出せる
    x.print_inner() 
}

fn fn_that_takes_option<T : std::fmt::Debug>(x: &Option<T>) {
    println!("{:?}", x)
}

関連

Deref型 - あるマのメモ書き

アンチパターン Deref ポリモフィズム - あるマのメモ書き

Deref in std::ops - Rust

Appendix

*演算子&演算子について

B - Operators and Symbols - The Rust Programming Language

演算子 説明
* *expr Dereference
& &expr, &mut expr Borrow