2019/03/27

Rustで演算子オーバーロード

やはり便利なtrait

Rustで自身が作成した独自の型(structなど)に演算機能を実装したい場合、traitを用いることで実現できます。
例えば、以下のような構造体を作成したとします。

#[derive(Debug, PartialEq)]
struct Number<N>(N);
実際にはこのような単純な構造体を作成することは無意味ではありますが、演算子オーバーロードの例としてわかりやすいかなと思います。
期待している結果は、Number(5) + Number(6) = Number(11)といったものです。
実現するためには、std::ops::Addというtraitを使います。そして以下のように書きます。

impl<N> Add for Number<N>
    where N: Add<Output=N>
{
    type Output = Self;
    
    fn add(self, rhs: Self) -> Self {
        Number(self.0 + rhs.0)
    }
} 
Selfは、上記の場合Numberと同じです。rhsはRight Hand Sideの略で、右辺ということです。この略語はソースコードを見ていると、時々出てきます。これで以下のようなコードを実行すると、期待した結果を得ることができます。

fn main() {
    let n1 = Number(5);
    let n2 = Number(6);
    assert_eq!(n1.add(n2), Number(11));
}
ここで実はAdd以外にも演算子オーバーロードの機能が実装されていることにお気づきでしょうか?実は#[derive(Debug, PartialEq)]PartialEqもまた演算子で、等価判定演算子といい、これはstd::cmp::PartialEqというtraitです。つまり、上記のNumber==!=を実装していることになります。したがって以下のようなことが可能です。

fn main() {
    let n1 = Number(255);
    let n2 = Number(255);
    assert_eq!(n1, n2);
}
この機能をうまく応用して、より効率的なコードを書けるようになりたいものです。