Rust学习笔记之面向对象编程

外界有多纷扰,内心就有多丰饶

大家好,我是柒八九

今天,我们继续Rust学习笔记的探索。我们来谈谈关于面向对象编程的相关知识点。

如果,想了解该系列的文章,可以参考我们已经发布的文章。如下是往期文章。

文章list

  1. Rust学习笔记之Rust环境配置和入门指南
  2. Rust学习笔记之基础概念
  3. Rust学习笔记之所有权
  4. Rust学习笔记之结构体
  5. Rust学习笔记之枚举和匹配模式
  6. Rust学习笔记之包、Crate和模块
  7. Rust学习笔记之集合
  8. Rust学习笔记之错误处理
  9. Rust学习笔记之泛型、trait 与生命周期
  10. Rust学习笔记之闭包和迭代器
  11. Rust学习笔记之智能指针
  12. Rust学习笔记之并发

你能所学到的知识点

  1. 编程范式 推荐阅读指数 ⭐️⭐️⭐️⭐️
  2. 面向对象编程 推荐阅读指数 ⭐️⭐️⭐️⭐️⭐️
  3. 面向对象在Rust中的体现 推荐阅读指数 ⭐️⭐️⭐️⭐️⭐️

好了,天不早了,干点正事哇。
Rust学习笔记之面向对象编程


编程范式

编程范式是一种编程的方法论或思维模式,它定义了一组规则、原则和约束,用于组织和结构化程序的设计和实现。

不同的编程范式提供了不同的思考方式和工作方式,以解决特定类型的问题和应对不同的编程场景。每种编程范式都基于一套独特的概念和原则,它们描述了程序员如何构建、组织和操作代码。编程范式指导程序员思考问题的方式,并提供了特定的语法和语义规则来实现代码。通过遵循特定的编程范式,程序员可以更好地组织代码、提高代码的可读性、可维护性和重用性。

常见的编程范式

编程范式 适用场景 主要编程语言
面向过程编程(Procedural Programming) 基于过程和函数的编程范式,通过定义一系列的过程和函数来实现程序的逻辑 C、Fortran、Pascal
面向对象编程(Object-Oriented Programming,OOP) 现实世界的事物抽象成对象,通过对象之间的交互和消息传递来实现程序的设计和开发。 Java、C++、Python、Ruby
函数式编程(Functional Programming) 计算视为函数求值的过程,强调无状态和不可变数据的使用,避免副作用,注重函数的组合和高阶函数的使用 Haskell、Lisp、Clojure、Scala
声明式编程(Declarative Programming) 描述问题的逻辑和规则,而不是明确指定解决问题的步骤,更关注”是什么”而非”如何” SQL、Prolog、XSLT、Haskell
响应式编程(Reactive Programming) 基于数据流和事件的编程范式,通过触发和响应事件来处理数据流和状态变化。
前端开发、事件驱动、用户界面交互、异步数据流处理
JavaScript、RxJava、React
过程式编程(Procedural Programming) 按照顺序执行指令的编程方式,强调控制流和算法的设计 Bash、Perl、Lua、Batch
指令式编程(Imperative Programming) 通过一系列的指令和语句来描述计算机的操作,强调修改和控制计算机状态。 Assembly、C、C++

需要注意的是,编程范式并不是互斥的,而是可以相互融合和组合使用的

例如,可以在面向对象编程中结合函数式编程的思想,或者在声明式编程中嵌入面向对象的概念。这种灵活的组合可以根据问题的需求和开发团队的偏好来决定。


面向对象编程

{面向对象编程|Object-Oriented Programming}OOP)是一种流行的编程范式,它以对象为核心,将数据和操作数据的方法封装在一起。面向对象编程强调对象之间的交互和消息传递,通过定义类、创建对象、继承和多态等概念来实现程序的设计和开发。

以下是面向对象编程的核心概念:

概念 描述
对象 (Object) 面向对象编程的基本单元,是类的实例,具有自己的状态和行为。
类 (Class) 定义对象的模板或蓝图,描述了对象的属性和行为
封装 (Encapsulation) 将数据和操作数据的方法封装在类中,隐藏内部实现细节,提供公共接口
继承 (Inheritance) 允许一个类继承另一个类的属性和方法,实现代码的重用和扩展
多态 (Polymorphism) 同一个方法可以根据对象的不同表现出不同的行为,提高代码的灵活性。
抽象 (Abstraction) 将问题简化为类、对象和方法的模型,提取关键特征和行为形成可重用模型。
信息隐藏 (Information Hiding) 将类的内部实现细节对外部隐藏,保护对象的状态,通过公共接口进行操作。
消息传递 (Message Passing) 通过对象之间的消息传递实现交互,对象可以发送消息请求执行方法。

对象是类的实例,类定义了对象的属性和行为。封装将数据和方法封装在类中,继承允许类继承另一个类的属性和方法。多态使得同一个方法可以根据对象的不同表现出不同行为。抽象将问题简化为模型,信息隐藏保护对象的状态。消息传递实现对象之间的交互和协作。

面向对象编程具有以下优点:

  1. 可重用性:通过封装、继承和多态,可以实现代码的重用,减少开发工作量。
  2. 可维护性:面向对象编程具有模块化和组件化的特性,使代码更易于理解、修改和扩展。
  3. 灵活性:多态和抽象概念

面向对象在Rust中的体现

面向对象编程语言所共享的一些特性往往是{对象|Object}{封装|Encapsulation}{继承|Inheritance}

对象包含数据和行为

Design Patterns是面向对象编程模式的目录。它这样定义面向对象编程:

面向对象的程序是由对象组成的。一个对象包含数据和操作这些数据的过程。这些过程通常被称为方法操作

在这个定义下,Rust 是面向对象的:

结构体枚举包含数据而 impl 块提供了在结构体和枚举之上的方法。虽然带有方法的结构体和枚举并不被称为对象,但是他们提供了与对象相同的功能。


封装隐藏了实现细节

另一个通常与面向对象编程相关的方面是 {封装|Encapsulation}的思想:对象的实现细节不能被使用对象的代码获取到。所以唯一与对象交互的方式是通过对象提供的公有 API;使用对象的代码无法深入到对象内部并直接改变数据或者行为。封装使得改变和重构对象的内部时无需改变使用对象的代码。

Rust中,可以使用 pub 关键字来决定模块、类型、函数和方法是公有的,而默认情况下其他一切都是私有的

可以定义一个包含一个 i32 类型 vector 的结构体 AveragedCollection 。结构体也可以有一个字段,该字段保存了 vector 中所有值的平均值。

pub struct AveragedCollection {
    list: Vec<i32>,
    average: f64,
}

结构体自身被标记为 pub,这样其他代码就可以使用这个结构体,但是在结构体内部的字段仍然是私有的

还可以在结构体上实现 addremoveaverage 方法。保证变量被增加到列表或者被从列表删除时,也会同时更新平均值。

impl AveragedCollection {
    pub fn add(&mut self, value: i32) {
        self.list.push(value);
        self.update_average();
    }

    pub fn remove(&mut self) -> Option<i32> {
        let result = self.list.pop();
        match result {
            Some(value) => {
                self.update_average();
                Some(value)
            },
            None => None,
        }
    }

    pub fn average(&self) -> f64 {
        self.average
    }

    fn update_average(&mut self) {
        let total: i32 = self.list.iter().sum();
        self.average = total as f64 / self.list.len() as f64;
    }
}

公有方法 addremoveaverage 是修改 AveragedCollection 实例的唯一方式。当使用 add 方法把一个元素加入到 list 或者使用 remove 方法来删除时,这些方法的实现同时会调用私有的 update_average 方法来更新 average 字段。


继承,作为类型系统与代码共享

{继承|Inheritance}是一个很多编程语言都提供的机制,一个对象可以定义为继承另一个对象的定义,这使其可以获得父对象的数据和行为,而无需重新定义

如果一个语言必须有继承才能被称为面向对象语言的话,那么 Rust 就不是面向对象的。无法定义一个结构体继承父结构体的成员和方法。

选择继承有两个主要的原因。

  • 第一个是为了重用代码:一旦为一个类型实现了特定行为,继承可以对一个不同的类型重用这个实现。相反 Rust 代码可以使用默认 trait 方法实现来进行共享。
  • 第二个使用继承的原因与类型系统有关:表现为子类型可以用于父类型被使用的地方。这也被称为 {多态|polymorphism},这意味着如果多种对象共享特定的属性,则可以相互替代使用。

近来继承作为一种语言设计的解决方案在很多语言中失宠了,因为其时常带有共享多于所需的代码的风险。子类不应总是共享其父类的所有特征,但是继承却始终如此。如此会使程序设计更为不灵活,并引入无意义的子类方法调用,或由于方法实际并不适用于子类而造成错误的可能性。某些语言还只允许子类继承一个父类,进一步限制了程序设计的灵活性。

因为这些原因,Rust 选择了一个不同的途径,使用 trait 对象而不是继承。


为使用不同类型的值而设计的 trait 对象

Rust 刻意不将结构体与枚举称为 “对象”,以便与其他语言中的对象相区别。在结构体或枚举中,结构体字段中的数据和 impl 块中的行为是分开的,不同于其他语言中将数据和行为组合进一个称为对象的概念中。trait 对象将数据和行为两者相结合,从这种意义上说 则 其更类似其他语言中的对象。不过 trait 对象不同于传统的对象,因为不能向 trait 对象增加数据。trait 对象并不像其他语言中的对象那么通用:其(trait 对象)具体的作用是允许对通用行为进行抽象


后记

分享是一种态度

参考资料:《Rust权威指南》

全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。

Rust学习笔记之面向对象编程

原文链接:https://juejin.cn/post/7243790811522318397 作者:前端小魔女

(0)
上一篇 2023年6月13日 上午10:16
下一篇 2023年6月13日 上午10:26

相关推荐

发表回复

登录后才能评论