• 运算符重载
    • 重载加法
    • 神奇的Output以及动态分发
    • 对范型的限制

    运算符重载

    Rust可以让我们对某些运算符进行重载,这其中大部分的重载都是对std::ops下的trait进行重载而实现的。

    重载加法

    我们现在来实现一个只支持加法的阉割版复数:

    1. use std::ops::Add;
    2. #[derive(Debug)]
    3. struct Complex {
    4. a: f64,
    5. b: f64,
    6. }
    7. impl Add for Complex {
    8. type Output = Complex;
    9. fn add(self, other: Complex) -> Complex {
    10. Complex {a: self.a+other.a, b: self.b+other.b}
    11. }
    12. }
    13. fn main() {
    14. let cp1 = Complex{a: 1f64, b: 2.0};
    15. let cp2 = Complex{a: 5.0, b:8.1};
    16. let cp3 = cp1 + cp2;
    17. print!("{:?}", cp3);
    18. }

    输出:

    1. Complex { a: 6, b: 10.1}

    这里我们实现了std::ops::Add这个trait。这时候有同学一拍脑门,原来如此,没错……其实Rust的大部分运算符都是std::ops下的trait的语法糖!

    我们来看看std::ops::Add的具体结构

    1. impl Add<i32> for Point {
    2. type Output = f64;
    3. fn add(self, rhs: i32) -> f64 {
    4. // add an i32 to a Point and get an f64
    5. }
    6. }

    神奇的Output以及动态分发

    有的同学会问了,这个Output是肿么回事?答,类型转换哟亲!
    举个不太恰当的栗子,我们在现实中会出现0.5+0.5=1这样的算式,用Rust的语言来描述就是: 两个f32相加得到了一个i8。显而易见,Output就是为这种情况设计的。

    还是看代码:

    1. use std::ops::Add;
    2. #[derive(Debug)]
    3. struct Complex {
    4. a: f64,
    5. b: f64,
    6. }
    7. impl Add for Complex {
    8. type Output = Complex;
    9. fn add(self, other: Complex) -> Complex {
    10. Complex {a: self.a+other.a, b: self.b+other.b}
    11. }
    12. }
    13. impl Add<i32> for Complex {
    14. type Output = f64;
    15. fn add(self, other: i32) -> f64 {
    16. self.a + self.b + (other as f64)
    17. }
    18. }
    19. fn main() {
    20. let cp1 = Complex{a: 1f64, b: 2.0};
    21. let cp2 = Complex{a: 5.0, b:8.1};
    22. let cp3 = Complex{a: 9.0, b:20.0};
    23. let complex_add_result = cp1 + cp2;
    24. print!("{:?}\n", complex_add_result);
    25. print!("{:?}", cp3 + 10i32);
    26. }

    输出结果:

    1. Complex { a: 6, b: 10.1 }
    2. 39

    对范型的限制

    Rust的运算符是基于trait系统的,同样的,运算符可以被当成一种对范型的限制,我们可以这么要求范型T必须实现了trait Mul<Output=T>
    于是,我们得到了如下的一份代码:

    1. use std::ops::Mul;
    2. trait HasArea<T> {
    3. fn area(&self) -> T;
    4. }
    5. struct Square<T> {
    6. x: T,
    7. y: T,
    8. side: T,
    9. }
    10. impl<T> HasArea<T> for Square<T>
    11. where T: Mul<Output=T> + Copy {
    12. fn area(&self) -> T {
    13. self.side * self.side
    14. }
    15. }
    16. fn main() {
    17. let s = Square {
    18. x: 0.0f64,
    19. y: 0.0f64,
    20. side: 12.0f64,
    21. };
    22. println!("Area of s: {}", s.area());
    23. }

    对于trait HasArea<T>和 struct Square<T>,我们通过where T: Mul<Output=T> + Copy 限制了T必须实现乘法。同时Copy则限制了Rust不再将self.side给move到返回值里去。

    写法简单,轻松愉快。