zoukankan      html  css  js  c++  java
  • Rust 学习之运算符重载

    Rust 学习之运算符重载

    最近一直在微信读书上阅读《深入浅出 Rust》,因为一直在地铁上阅读,导致没办法在阅读到的知识点立即验证和实践,从而阅读效果不佳。借着此次有时间,记录一下其中的运算符重载。

    关于运算符重载,在《Rust 编程语言》中没有找到相关章节,但在《Rust 基础》(英文名是 RustPrimer)中找到了相关章节

    所谓运算符,百度的定义如下:

    运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

    通俗的讲,就是自定义一些运算符的功能,使代码看起来支持一些特殊数据类型的运算。

    此外,《通过例子学 Rust》的描述感觉更易懂:

    在 Rust 中,很多运算符可以通过 trait 来重载。也就是说,这些运算符可以根据它们的 输入参数来完成不同的任务。这之所以可行,是因为运算符就是方法调用的语法糖。例 如,a + b 中的 + 运算符会调用 add 方法(也就是 a.add(b))。这个 add 方 法是 Add trait 的一部分。因此,+ 运算符可以被任何 Add trait 的实现者使用。

    首先我们通过 Rust 标准库文档的例子入门:

    use std::ops::{Add, Sub, Mul, Div};
    
    #[derive(Debug, PartialEq)]
    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}
        }
    }
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn test_point_add() {
            assert_eq!(Point {x: 3, y: 3} + Point {x: 4, y: 4}, Point {x: 7, y: 7});
        }
    }
    

    上面的代码中,声明了一个新的类型 Point,随后,为这个类型实现了 Add trait,这样,在一个表达式中,对 Point 类型的数据进行了 + 运算时,就会调用 trait 中的 add 方法,实现 Point 类型的数据的相加。

    模拟实现 PHP 中数组的 +

    因为最熟悉的语言是 PHP,对 PHP 中数组的 + 运算尤为深刻。所以打算对 Rust 数组也实现类似的功能。

    PHP 中两个数组相加,有点类似于 merge,但跟 merge 又有所区别:如果第一个数组中的某个元素下标已存在,则会忽略第二个数组中相同下标的元素;如果下标 a 在第 1 个数组中不存在,则将第 2 个数组中该下标对应的元素 merge 到新数组中。比如:

    $a1  = [1,2,3];
    $a2 = [3,4,5,6,7];
    var_dump($a1 + $a2);
    

    $a1$a2 相加后,最终的结果是:[1, 2, 3, 6, 7]。因为 $a2345 对应的下标是 012,而这几个下标在 $a1 中是已存在的。因此忽略。只将元素 67 merge 进新数组。

    我们再看下 Rust 中数组相加默认是什么行为:

    #[test]
    fn test_vec_plus() {
        let a1: Vec<u32> = vec![1,2,3];
        let a2: Vec<u32> = vec![1,2,4,5,6];
        let a3 = a1 + a2;
        println!("{}-{}", a1, a3)
        assert!(false);
    }
    

    运行测试用例 cargo t -- notes::op_rhs::tests

    error[E0369]: cannot add `std::vec::Vec<u32>` to `std::vec::Vec<u32>`
      --> src/notes/op_rhs.rs:33:21
       |
    33 |         let a3 = a1 + a2;
       |                  -- ^ -- std::vec::Vec<u32>
       |                  |
       |                  std::vec::Vec<u32>
       |
       = note: an implementation of `std::ops::Add` might be missing for `std::vec::Vec<u32>`
    

    很遗憾,Rust 默认对 Vec<i32> 类型没有实现 + 的运算符重载。那我们尝试自己手动实现吧。

    由于 Rust 的 Orphan 规则,我们不能对标准库中的 Vec 实现 Add trait,因此,必须得用自己定义的类型包装一下:

    #[derive(Debug, PartialEq)]
    struct MyVec(Vec<u32>);
    

    针对 MyVec 类型 Add trait,即实现 add 方法:

    fn add(self, other: MyVec) -> MyVec {
        if self.0.is_empty() {
            return other;
        }
        let mut v3: Vec<u32> = Vec::new();
        self.0.iter().for_each(|x| v3.push(*x));
        let len1 = self.0.len();
        let len2 = other.0.len();
        if len1 < len2 {
            for i in len1..len2 {
                v3.push(other.0[i]);
            }
        }
        MyVec(v3)
    }
    

    最后,写一个测试用例:

    #[test]
    fn test_vec_plus() {
        let a1: MyVec = MyVec(vec![1,2,3]);
        let a2: MyVec = MyVec(vec![1,2,4,5,6]);
        let a3: MyVec = a1 + a2;
        assert_eq!(a3, MyVec(vec![1,2,3,5,6]))
    }
    

    完整源代码参考这里

    参考资料

  • 相关阅读:
    利用webpack构建vue项目
    关于写毕业设计网页代码写后感
    用canvas属性写一个五角星哦
    css3瀑布流布局
    css3学习笔记,随时帮你记起遗忘的css3
    自己做得一个用于直观观察css3 transform属性中的rotate 3D效果
    第一次讨论——关于块级元素与行内元素的区别,浮动与清除浮动,定位,兼容性问题
    软件工程第一次作业
    自我介绍
    自我介绍
  • 原文地址:https://www.cnblogs.com/ishenghuo/p/13696576.html
Copyright © 2011-2022 走看看