📚

Rustで使える演算子オーバーロード(C++との比較)

に公開
演算子 C++ Rust Rustトレイト 備考
+ Add
- Sub
* Mul
/ Div
% Rem
+= AddAssign
-= SubAssign
*= MulAssign
/= DivAssign
%= RemAssign
==/!= PartialEq !===で自動実装
<,>,<=,>= PartialOrd すべてPartialOrdで自動実装
! Not 単項否定
~ Rustでビット演算(NOT)は!を使用
& BitAnd ビット演算(AND)
| BitOr ビット演算(OR)
^ BitXor ビット演算(XOR)
&= BitAndAssign
=| BitOrAssign
^= BitXorAssign
<< Shl シフト
>> Shr
<<= ShlAssign
>>= ShrAssign
[] Index, IndexMut
() Fn, FnMut, FnOnce クロージャ呼び出し
-> Rustでは意味が異なるためオーバーロード不可
->*
=(代入) Rustでは代入演算子自体のオーバーロード不可
++/-- Rustは副作用排除のため非対応
,(カンマ) Rustでは演算子として扱わない
new/delete Rustは所有権・安全性モデルが異なるため非対応

The Rust Programming Language 日本語版 付録B: 演算子と記号
Rust By Example 日本語版 演算子のオーバーロード
std::ops

書き方

pub struct StructName {
    value: u32,
}
impl StructName {
    // struct.add(other)という呼び方も残したいのでこの関数はそのまま
    pub fn add(&self, other: Self) -> Self {
        StructName {
            value: self.value + other.value,
        }
    }

    // 1回内部関数を噛ませることにより上のaddが呼べる(実質処理が無いのでinline)
    #[inline]
    fn add_internal(self, other: Self) -> Self {
        self.add(other)
    }
}

// 同じ型を対象にする場合は型指定なし。
impl std::ops::Add for StructName {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        self.add_internal(other)   // add内で直接self.addを呼ぶと循環参照となる。
    }
}
// 別の型を対象にしたい場合はAdd<T>とする。
impl std::ops::Add<u32> for StructName {
    type Output = Self;

    fn add(self, other: u32) -> Self {
        StructName {
            value: self.value + other,
        }
    }
}
// 逆順を定義したい場合はこんな感じ
impl std::ops::Add<StructName> for u32 {
    type Output = StructName;

    fn add(self, other: StructName) -> StructName {
        StructName {
            value: self + other.value,
        }
    }
}

add内での呼び出し関数がここでadd_internalとしたのは元々内部でadd関数を定義していたため、struct.add()という呼び出しを残すため、StructNameにadd(元々実装していた関数)を呼ぶためのadd_internalを追加した。
もちろんそのような柵がなければ演算子関数の中で直接計算してよい。

Discussion