運算子重載嘛,可以對自己定義的struct 或是enum 使用運算子,這樣就能寫出Vec3 + Vec3 這樣比較漂亮的寫法,不用Vec3.add(Vec3),啊雖然兩個本質上沒什麼兩樣啦
這章定義一個Sign的類別,分為<正>、<負>、<零>和<未知>,我們要實作他的乘法和加法:
enum Sign { POSITIVE, NEGATIVE, ZERO, UNKNOWN, }
Rust可重載的運算子可以在這裡找到:
https://doc.rust-lang.org/std/ops/index.html
另外是比較運算子,包括PartialEq 跟PartialOrd:
https://doc.rust-lang.org/std/cmp/
例如我們要重載乘法運算子,以下是網站上的定義:
實作時當然就是先以use這個trait,然後實作這trait並加入相關的函式:
https://doc.rust-lang.org/std/cmp/
例如我們要重載乘法運算子,以下是網站上的定義:
pub trait Mul<RHS = Self> {
type Output;
fn mul(self, rhs: RHS) -> Self::Output;
}
type Output;
fn mul(self, rhs: RHS) -> Self::Output;
}
實作時當然就是先以use這個trait,然後實作這trait並加入相關的函式:
use std::ops::Mul; impl Mul for Sign { type Output = Sign; fn mul(self, rhs: Self) -> Self { if self == Sign::ZERO || rhs == Sign::ZERO { Sign::ZERO } else if self == Sign::UNKNOWN || rhs == Sign::UNKNOWN { Sign::UNKNOWN } else if self == rhs { Sign::POSITIVE } else { Sign::NEGATIVE } } }這樣就完成了,現在我們就能這樣寫了:
assert_eq!(Sign::NEGATIVE, Sign::POSITIVE * Sign::NEGATIVE);
另外常遇到的問題是,將運算子重載和Rust 的泛型一起用時,例如,我們定義sum_of_square 這個function,並希望使用泛型:
fn inner_product<T: Copy>(lhs: T, rhs: T) -> T {
lhs*lhs + rhs*rhs
}
這樣編譯並不會過,因為泛型T 並不適用乘法跟加法,我們需要告訴編譯器,只有實作Mul跟Add trait的型別才能通過。同時指定Output 型別同樣為T,文件上並沒有講如何實作這部分,我忘記是在哪找到要這樣寫的,就為了那個Output=T花了我超多時間RRRRR,反正Rust 的文件就是這樣…lhs*lhs + rhs*rhs
}
fn inner_product<T: Mul<T, Output=T>+Add<T, Output=T>+Copy>
如果你要不同的實作,例如我要能夠跟i32 相加,那就是:
fn foo<T: Add<i32, Output=T>>(x: T) -> T { x+1 }
個人覺得:相較之下,C++運算子重載的語法真的相當的複雜(事實上我覺得我已經不會寫了Orz),rust 簡潔不少,使用trait 中的function name來實作也比C++ 用 operator+, operator* 好讀很多。
有關於文中所提Sign 的實作,可見:
https://github.com/yodalee/computationbook-rust/blob/master/programming_in_toyland/signs/sign.rs