演算子のオーバーロード
Rustでは、多くの演算子はトレイトによってオーバーロードすることができます。つまり、一部の演算子は引数となる値の型に応じて異なる役割を果たすことができるということです。これが可能なのは、演算子が実際にはメソッド呼び出しの糖衣構文にすぎないからです。例えばa + bにおける+演算子はaddメソッドを(a.add(b)の形で)呼び出します。このaddメソッドはAddトレイトの一部です。それ故、+はAddトレイトを実装している全ての型に対して有効なのです。
Addなどの、演算子をオーバーロードするトレイトの一覧はcore::opsにあります。
use std::ops;
struct Foo;
struct Bar;
#[derive(Debug)]
struct FooBar;
#[derive(Debug)]
struct BarFoo;
// `std::ops::Add`トレイトは`+`の振る舞いを規定するために使用されます。
// ここでは`Foo`に対して`Add<Bar>`を実装します。これは加算時の右辺が`Bar`型
// の時に呼び出されるトレイトです。
// つまり以下は`Foo + Bar = FooBar`という振る舞いをもたらします。
impl ops::Add<Bar> for Foo {
type Output = FooBar;
fn add(self, _rhs: Bar) -> FooBar {
println!("> Foo.add(Bar) was called");
FooBar
}
}
// 型を反転することで、非可換の加算を実装できます。ここでは`Bar`に対して
// `Add<Foo>`を実装します。
// これは加算時の右辺が`Foo`型の時に呼び出されるメソッドです。
// つまり以下は`Bar + Foo = BarFoo`という結果をもたらします。
impl ops::Add<Foo> for Bar {
type Output = BarFoo;
fn add(self, _rhs: Foo) -> BarFoo {
println!("> Bar.add(Foo) was called");
BarFoo
}
}
fn main() {
println!("Foo + Bar = {:?}", Foo + Bar);
println!("Bar + Foo = {:?}", Bar + Foo);
}