Rust 学习笔记:面向对象语言的特点

Rust 学习笔记:面向对象语言的特点

在编程社区中,对于一门语言必须具备哪些特性才能被认为是面向对象的,并没有达成共识。

面向对象语言具有某些共同的特征,即对象、封装和继承。让我们看看这些特征的含义以及 Rust 是否支持它们。

对象包含数据和行为

《设计模式:可重用面向对象软件的元素》一书是这样定义 OOP 的:

面向对象程序是由对象组成的。对象将数据和对该数据进行操作的过程打包。这些过程通常称为方法或操作。

使用这个定义,Rust 是面向对象的:结构体和枚举具有数据,而 impl 块提供结构体和枚举的方法。尽管带方法的结构体和枚举不称为对象,但它们提供了相同的功能。

封装隐藏了实现细节

与 OOP 相关的另一个方面是封装的思想,这意味着使用该对象的代码无法访问对象的实现细节。因此,与对象交互的唯一方法是通过它的公共 API。使用对象的代码不应该能够进入对象的内部并直接更改数据或行为。这使程序员能够更改和重构对象的内部结构,而无需更改使用该对象的代码。

我们可以使用 pub 关键字来决定代码中的哪些模块、类型、函数和方法应该是公共的,而默认情况下,其他的都是私有的。

例如,我们可以定义一个结构体 AveragedCollection,它有一个包含 i32 值的数组的字段。该结构体还可以有一个字段,包含向量中值的平均值,这意味着当任何人需要它时,不必根据需要计算平均值。换句话说, AveragedCollection 将为我们缓存计算出的平均值。

AveragedCollection 结构体的定义:

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

该结构体被标记为 pub,以便其他代码可以使用它,但结构体中的字段仍然是私有的。

我们希望确保每当从列表中添加或删除值时,平均值也会更新。我们通过在结构体上实现 add、remove 和 average 方法来实现这一点:

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;
    }
}

我们将 list 和 average 字段保留为私有,公共方法 add、remove 和 average 是访问或修改 AveragedCollection 实例中的数据的唯一方法。当使用 add 方法将项添加到列表中或使用 remove 方法删除项时,每个项的实现都会调用私有的 update_average 方法,该方法也会处理平均字段的更新。average 方法返回 average 字段中的值,允许外部代码读取平均值,但不能修改它。

如果封装是一种语言被认为是面向对象的必要方面,那么 Rust 就满足了这个要求。对代码的不同部分使用 pub 或不使用 pub 的选项支持对实现细节进行封装。

作为类型系统和代码共享的继承

继承是一种机制,对象可以从另一个对象的定义中继承元素,从而获得父对象的数据和行为,而不必重新定义它们。

如果一种语言必须具有继承才能是面向对象的,那么 Rust 就不是这样的语言。如果不使用宏,就无法定义继承父结构的字段和方法实现的结构。

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

一种是代码重用:为一种类型实现特定的行为,继承使能够为另一种类型重用该实现。在 Rust 代码中,你可以使用默认的 trait 方法实现以有限的方式做到这一点。

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

我们在 Summary trait 上添加了一个 summarize 方法的默认实现。任何实现 Summary trait 的类型都可以在其上使用 summarize 方法,而无需任何进一步的代码。这类似于父类具有方法的实现,继承子类也具有该方法的实现。当我们实现 Summary trait 时,我们也可以覆盖 summarize 方法的默认实现,这类似于子类覆盖从父类继承的方法的实现。

使用继承的另一个原因与类型系统有关:使子类型能够在与父类型相同的位置使用。这也称为多态性,这意味着如果多个对象共享某些特征,则可以在运行时相互替换。Rust 使用泛型来抽象不同可能的类型和 trait 约束,以对这些类型必须提供的内容施加约束。这有时被称为有界参数多态性。

在许多编程语言中,继承作为一种编程设计解决方案最近已经不受欢迎了,因为它经常冒着共享不必要的代码的风险。子类不应该总是共享父类的所有特征,但继承时会这样做。这可能会使程序设计的灵活性降低。它还引入了在子类上调用没有意义的方法或由于方法不适用于子类而导致错误的可能性。此外,一些语言只允许单继承(意味着子类只能继承一个类),这进一步限制了程序设计的灵活性。

由于这些原因,Rust 采用了使用 trait 对象而不是继承的不同方法。

内容概要:本文档详细介绍了利用Google Earth Engine (GEE) 平台对指定区域(位于中国广东省某地)进行遥感影像处理的一系列操作。首先,定义了研究区边界,并选取了 Landsat 8 卫星2023年8月至10月期间的数据,通过去云处理、归一化等预处理步骤确保数据质量。接着,基于预处理后的影像计算了地表温度(LST)、归一化植被指数(NDVI)、湿度指数(WET)、建筑指数(NDBSI)四个关键指标,并进行了主成分分析(PCA),提取出最重要的信息成分。为了进一步优化结果,还应用了像素二元模型对主成分分析的第一主成分进行了条件规范化处理,生成了最终的环境状态评估指数(RSEI)。最后,利用JRC全球表面水体数据集对水体区域进行了掩膜处理,保证了非水体区域的有效性。所有处理均在GEE平台上完成,并提供了可视化展示及结果导出功能。 适合人群:具备地理信息系统基础知识,对遥感影像处理有一定了解的研究人员或技术人员。 使用场景及目标:① 对特定区域的生态环境状况进行定量评估;② 为城市规划、环境保护等领域提供科学依据;③ 掌握GEE平台下遥感影像处理流程和技术方法。 其他说明:本案例不仅展示了如何使用GEE平台进行遥感影像处理,还涵盖了多种常用遥感指标的计算方法,如LST、NDVI等,对于从事相关领域的科研工作者具有较高的参考价值。此外,文中涉及的代码可以直接在GEE代码编辑器中运行,便于读者实践操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值