【跟小嘉学 Rust 编程】十七、面向对象语言特性

本文介绍了Rust中的面向对象特性,如数据和行为的概念,以及如何使用trait对象存储不同类型值、动态与静态派发的区别。同时探讨了状态模式在Rust中的应用,展示了如何通过trait实现代码复用和面向对象设计模式。
摘要由CSDN通过智能技术生成

系列文章目录

【跟小嘉学 Rust 编程】一、Rust 编程基础
【跟小嘉学 Rust 编程】二、Rust 包管理工具使用
【跟小嘉学 Rust 编程】三、Rust 的基本程序概念
【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念
【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据
【跟小嘉学 Rust 编程】六、枚举和模式匹配
【跟小嘉学 Rust 编程】七、使用包(Packages)、单元包(Crates)和模块(Module)来管理项目
【跟小嘉学 Rust 编程】八、常见的集合
【跟小嘉学 Rust 编程】九、错误处理(Error Handling)
【跟小嘉学 Rust 编程】十、泛型(Generic Type)、特征(Trait)和生命周期(Lifetimes)
【跟小嘉学 Rust 编程】十一、编写自动化测试
【跟小嘉学 Rust 编程】十二、构建一个命令行程序
【跟小嘉学 Rust 编程】十三、函数式语言特性:迭代器和闭包
【跟小嘉学 Rust 编程】十四、关于 Cargo 和 Crates.io
【跟小嘉学 Rust 编程】十五、智能指针(Smart Point)
【跟小嘉学 Rust 编程】十六、无畏并发(Fearless Concurrency)
【跟小嘉学 Rust 编程】十七、面向对象语言特性

前言

本章节讲解面向对象的特征,以及这些特征如何转化为 Rust。

主要教材参考 《The Rust Programming Language》


一、 面向对象语言特性

1.1、对象包含数据(Data)和行为(Behavior)

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

基于此定义,Rust 是面向对象的。 Struct、emun包含数据,impl 块为之提供了方法,但是带有方法的 Struct、 enum 并没被称为对象。

1.2、封装隐藏实现细节

封装:调用对象外部的代码无法直接访问对象内部的实现细节,唯一可以与对象进行交互的方法就是通过它公开的API。

Rust 里面使用 pub 公开数据或方法,默认是私有的。

1.3、继承和代码复用

继承:使对象可以沿用另外一个对象的数据和行为,且无需重复定义相关代码。

Rust 没有继承。

使用继承的原因:

  • 代码复用:Rust 使用 Trait方法来进行代码共享
  • 多态:Rust 使用泛型 和 trait 约束(限定参数化多态 bounded parametric)

二、使用 trait 对象存储不同类型的值

2.1、为共有行为定义为一个 trait


pub trait Draw{
	fn draw(&self);
}

2.2、动态派发(dynamic dispatch):和静态派发(static dispatch)

Trait 对象执行的是动态派发,将Trait约束作用于泛型,Rust 编译器会执行单态化,编译器会为我们用来替换泛型类型参数的每个具体类型生成对应函数和方法的非泛型实现。

通过态化生成的代码会执行静态派发(static dispatch),在编译过程中确定调用的具体方法

动态派发(dynamic dispatch): 无法确定在编译过程中你调用究竟是哪一种方法,编译器会产生额外的代码以便在运行时找出希望调用的方法

使用 trait 对象会执行动态派发,产生运行时开销,阻止编译器内联方法代码,使得部分优化操作无法进行。

trait 对象必须保证对象安全

2.3、Trait 对象必须保证对象安全

只能把满足对象安全的trait 转化 trait 对象
Rust 采用一系列规则来判定某个对象是否安全,只需要记住两条

  • 方法的返回类型不是 Self
  • 方法中不包含任何泛型类型参数

三、实现面向对象设计模式

3.1、状态模式(state pattern)

状态模式是一种面向对象设计模式,一个值拥有内部状态由数个状态对象(state object) 表达而成,而值的行为则随着内部状态的改变而改变

使用状态模式意味着

  • 业务需求变化时,不需要修改持有状态的值的代码,或者使用这个值的代码
  • 只需要更新状态对象内部的代码,以便改变其规则或增加一些新的状态对象

3.2、示例代码

pub struct Post {
    state: Option<Box<dyn State>>,
    content: String,
}

impl Post {
    pub fn new() -> Post {
        Post {
            state: Some(Box::new(Draft {})),
            content: String::new(),
        }
    }
    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
  	pub fn content(&self) -> &str {
        self.state.as_ref().unwrap().content(self)
    }
    pub fn request_review(&mut self) {
        if let Some(s) = self.state.take() {
            self.state = Some(s.request_review())
        }
    }
}

trait State {
  fn request_review(self: Box<Self>) -> Box<dyn State>;
  fn content<'a>(&self, post: &'a Post) -> &'a str {
        ""
    }
}

struct Draft {}

impl State for Draft {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        Box::new(PendingReview {})
    }
}

struct PendingReview {}

impl State for PendingReview {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        self
    }
}

struct Published {}

impl State for Published {
    fn request_review(self: Box<Self>) -> Box<dyn State> {
        self
    }

    fn approve(self: Box<Self>) -> Box<dyn State> {
        self
    }
     fn content<'a>(&self, post: &'a Post) -> &'a str {
        &post.content
    }
}

缺点

  • 某些状态之间是相互耦合的
  • 需要重复实现一些逻辑代码

3.3、

总结

以上就是今天要讲的内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小嘉丶学长

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

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

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

打赏作者

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

抵扣说明:

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

余额充值