注意: 最新版のドキュメントをご覧ください。この第1版ドキュメントは古くなっており、最新情報が反映されていません。リンク先のドキュメントが現在の Rust の最新のドキュメントです。
Rustは制限された形式での演算子オーバーロードを提供しており、オーバーロード可能な演算子がいくつか存在します。 型同士の間の演算子をサポートするためのトレイトが存在し、それらを実装することで演算子をオーバーロードできます。
たとえば、 +
の演算子は Add
トレイトでオーバーロードできます:
use std::ops::Add; #[derive(Debug)] struct Point { x: i32, y: i32, } impl Add for Point { type Output = Point; fn add(self, other: Point) -> Point { Point { x: self.x + other.x, y: self.y + other.y } } } fn main() { let p1 = Point { x: 1, y: 0 }; let p2 = Point { x: 2, y: 3 }; let p3 = p1 + p2; println!("{:?}", p3); }
main
中で、2つの Point
に対して +
を使えます。
これは Point
に対して Add<Output=Point>
を実装したためです。
同じ方法でオーバーロード可能な演算子が多数あります。
それらに対応したトレイトは std::ops
モジュール内に存在します。
全てのオーバーロード可能な演算子と対応するトレイトについては std::ops
のドキュメントを読んで確認して下さい。
それらのトレイトの実装は、ある一つのパターンに従います。
Add
トレイトを詳しく見ていきましょう:
pub trait Add<RHS = Self> { type Output; fn add(self, rhs: RHS) -> Self::Output; }
関連する3つの型が存在します: impl Add
を実装するもの、 デフォルトが Self
の RHS
、 そして Output
です。
たとえば、式 let z = x + y
においては x
は Self
型 y
は RHS、 z
は Self::Output
型となります。
impl Add<i32> for Point { type Output = f64; fn add(self, rhs: i32) -> f64 { // i32をPointに加算しf64を返す } }
上のコードによって以下の様に書けるようになります:
fn main() { let p: Point = // ... let x: f64 = p + 2i32; }let p: Point = // ... let x: f64 = p + 2i32;
オペレータトレイトがどのように定義されているかを学びましたので、トレイトについての章 の HasArea
トレイトと Square
構造体をさらに一般的に定義できます:
use std::ops::Mul; trait HasArea<T> { fn area(&self) -> T; } struct Square<T> { x: T, y: T, side: T, } impl<T> HasArea<T> for Square<T> where T: Mul<Output=T> + Copy { fn area(&self) -> T { self.side * self.side } } fn main() { let s = Square { x: 0.0f64, y: 0.0f64, side: 12.0f64, }; println!("Area of s: {}", s.area()); }
HasArea
と Square
について、型パラメータ T
を宣言し f64
で置換しました。
impl
はさらに関連する修正を必要とします:
impl<T> HasArea<T> for Square<T> where T: Mul<Output=T> + Copy { ... }
area
メソッドは辺を掛けることが可能なことを必要としています。
そのため型 T
が std::ops::Mul
を実装していなければならないと宣言しています。
上で説明した Add
と同様に、Mul
は Output
パラメータを取ります:
数値を掛け算した時に型が変わらないことを知っていますので、 Output
も T
と設定します。
また T
は、Rustが self.side
を返り値にムーブするのを試みないようにコピーをサポートしている必要があります。