30天拿下Rust之面向对象

简介: 30天拿下Rust之面向对象


概述

在编程语言的世界中,Rust以其独特的内存安全、并发控制和高性能特性吸引了众多开发者。虽然Rust并非传统的面向对象编程语言(比如:C++、Java),但它依然支持并提供了一种颇具特色的面向对象编程方式,以实现类似于面向对象的编程范式。

在Rust中,没有类的概念,但提供了模块、结构体、枚举、Trait来模拟面向对象编程的三大特性:封装、继承和多态。下面,我们分别进行介绍。



封装

Rust的封装机制提供了一种强大的方式来隐藏实现细节,仅暴露必要的接口给使用者。封装是面向对象编程的三大基本特性之一,它有助于创建模块化的代码,提高代码的可维护性和安全性。在Rust中,封装主要通过模块、结构体、私有性等特性来实现。

Rust使用模块来组织代码,每个模块都有自己的作用域,可以包含函数、类型定义、其他模块等。模块提供了一种自然的封装方式,可以将相关的代码组织在一起,并通过pub关键字来控制哪些内容对外部可见。在之前的专栏文章中,我们曾专门介绍过模块,故这里就不再进一步展开了。

在Rust中,结构体的字段可以通过指定访问修饰符来控制其可见性。默认情况下,字段是私有的,这意味着它们只能在定义结构体的模块内部被访问。通过pub关键字,我们可以将字段设置为公有,以便在外部访问。

我们在下面的my_module.rs文件中声明了公开的函数public_func和公开的结构体PublicStruct。private_func函数由于没有使用pub关键字,默认为私有的。

// my_module.rs
pub fn public_func() {
    // ...
}

fn private_func() {
    // ...
}

pub struct PublicStruct {
    pub public_field: i32,
}

接着,我们在下面的main.rs文件中使用了模块my_module中的函数和结构体。由于private_func是私有的,因此,无法使用use关键字导入,编译会提示错误:function `private_func` is private。

// main.rs
mod my_module;

use my_module::PublicStruct;
use my_module::public_func;
// 错误:该函数是私有的,无法使用
use my_module::private_func;

fn main() {
    let data = PublicStruct { public_field: 66 };
    println!("{}", data.public_field);
    public_func();
}

继承

Rust并没有传统意义上的继承机制,更倾向于使用组合和Trait来复用和扩展代码。然而,通过一些模式,我们可以在Rust中实现类似继承的效果。

使用组合模拟继承

可以通过将一个类型作为另一个类型的字段来实现组合,这可以模拟继承中子类包含父类字段的效果。

struct Parent {
    value: i32,
}

impl Parent {
    fn do_something(&self) {
        println!("parent data: {}", self.value);
    }
}

struct Child {
    parent: Parent,
    extra_value: String,
}

impl Child {
    fn new(value: i32, extra_field: String) -> Child {
        Child {
            parent: Parent { value },
            extra_value: extra_field,
        }
    }

    fn do_child_thing(&self) {
        println!("child data: {}", self.extra_value);
    }

    // 委托给父类的方法
    fn do_something(&self) {
        self.parent.do_something();
    }
}

fn main() {
    let child = Child::new(66, "World".to_string());
    // 调用父类的方法
    child.do_something();
    // 调用子类的方法
    child.在上面的示例代码中,Child结构体包含一个Parent类型的字段parent。这允许Child访问和调用Parent的方法,从而模拟了继承的行为。同时,Child还可以添加自己的字段和方法。

使用Trait模拟接口继承

Trait在Rust中类似于接口,它们定义了一组方法签名,可以由不同的类型来实现,这可以模拟接口继承的效果。o_child_thing();
}

在上面的示例代码中,Child结构体包含一个Parent类型的字段parent。这允许Child访问和调用Parent的方法,从而模拟了继承的行为。同时,Child还可以添加自己的字段和方法。

使用Trait模拟接口继承

Trait在Rust中类似于接口,它们定义了一组方法签名,可以由不同的类型来实现,这可以模拟接口继承的效果。

trait Animal {
    fn speak(&self);
}

struct Dog {
    name: String,
}

impl Animal for Dog {
    fn speak(&self) {
        println!("dog {} speak", self.name);
    }
}

struct Cat {
    name: String,
}

impl Animal for Cat {
    fn speak(&self) {
        println!("cat {} speak", self.name);
    }
}

fn animal_speak(animal: &dyn Animal) {
    animal.speak();
}

fn main() {
    let dog = Dog { name: "Buddy".to_string() };
    let cat = Cat { name: "Whiskers".to_string() };

    animal_speak(&dog);
    animal_speak(&cat);
}

在上面的示例代码中,我们定义了一个Animal特征,它有一个speak方法。Dog和Cat结构体都实现了Animal特征,因此它们都可以被视为动物,并且具有speak方法。通过动态分发(使用&dyn Animal),我们可以编写接受任何实现了Animal特征的类型的函数,比如这里的animal_speak。

多态

在Rust中,多态通常是通过Trait和泛型来实现的。多态允许我们编写灵活的代码,这些代码可以处理多种不同的类型,只要这些类型满足某些共同的接口或约束。Trait定义了类型必须实现的方法集合,从而允许我们编写与这些类型交互的通用代码。在上面介绍继承的示例代码中,我们已经看到了基于Trait的多态实现,故这里就不再赘述了。

接下来,我们使用泛型来实现多态。泛型允许我们编写可以处理多种类型的函数或结构体,而不需要在编译时指定具体的类型。

fn find_max<T: Ord>(slice: &[T]) -> &T {
    let mut max = &slice[0];
    for item in slice.iter() {
        if item > max {
            max = item;
        }
    }
    max
}

fn main() {
    let numbers = vec![66, 99, 100, 50];
    let max_number = *find_max(&numbers);
    println!("{}", max_number);

    let fruits = vec!["Lemon", "Apple", "Date"];
    let max_fruit = find_max(&fruits);
    println!("{}", max_fruit);
}

在上面的示例代码中,我们定义了一个泛型函数find_max,它接受一个实现了Ord特征(即可以排序的类型)的切片,并返回其中的最大值。由于Ord特征是由多种标准库类型实现的,我们可以使用这个函数来找出整数切片中的最大值,或字符串切片中基于字典序的最大字符串。

总结

虽然Rust并不是传统意义上的面向对象编程语言,但它提供了丰富的工具来模拟和实现面向对象的概念。通过结构体与方法的组合、Trait与接口的定义、泛型的使用,Rust可以让我们以面向对象的方式来组织和封装代码,实现高内聚、低耦合的代码结构。正是这种灵活性,使得Rust能够适应各种复杂的编程需求,成为系统级编程的理想选择。


相关文章
|
12天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
8天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2522 18
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
8天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1525 15
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
4天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
10天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
596 14
|
1月前
|
运维 Cloud Native Devops
一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
19283 30
|
10天前
|
人工智能 自动驾驶 机器人
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
过去22个月,AI发展速度超过任何历史时期,但我们依然还处于AGI变革的早期。生成式AI最大的想象力,绝不是在手机屏幕上做一两个新的超级app,而是接管数字世界,改变物理世界。
498 49
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
|
1月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
18845 20
|
1月前
|
Rust Apache 对象存储
Apache Paimon V0.9最新进展
Apache Paimon V0.9 版本即将发布,此版本带来了多项新特性并解决了关键挑战。Paimon自2022年从Flink社区诞生以来迅速成长,已成为Apache顶级项目,并广泛应用于阿里集团内外的多家企业。
17530 13
Apache Paimon V0.9最新进展
|
3天前
|
云安全 存储 运维
叮咚!您有一份六大必做安全操作清单,请查收
云安全态势管理(CSPM)开启免费试用
368 4
叮咚!您有一份六大必做安全操作清单,请查收