Rust编程语言入门之Rust的面向对象编程特性
(相关资料图)
Rust 的面向对象编程特性
一、面向对象语言的特性
Rust是面向对象编程语言吗?
- Rust 受到多种编程范式的影响,包括面向对象
- 面向对象通常包含以下特性:命名对象、封装、继承
对象包含数据和行为
- “设计模式四人帮”在《设计模型》中给面向对象的定义:
- 面向对象的程序由对象组成
- 对象包装了数据和操作这些数据的过程,这些过程通常被称作方法或操作
- 基于此定义:Rust是面向对象的
- struct、enum 包含数据
- impl 块为之提供了方法
- 但带有方法的 struct、enum 并没有被称为对象
封装
- 封装:调用对象外部的代码无法直接访问对象内部的实现细节,唯一可以与对象进行交互的方法就是通过它公开的 API
- Rust:pub 关键字
pub struct AveragedCollection { list: Vec, average: f64,}impl AveragedCollection { pub fn add(&mut self, value: i32) { self.list.push(value); self.update_average(); } pub fn remove(&mut self) -> Option { 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; }}
继承
- 继承:使对象可以沿用另外一个对象的数据和行为,且无需重复定义相关代码
- Rust:没有继承
- 使用继承的原因:
- 代码复用
- Rust:默认 trait 方法来进行代码共享
- 多态
- Rust:泛型和 trait 约束(限定参数化多态 bounded parametric)
- 代码复用
- 很多新语言都不使用继承作为内置的程序设计方案了。
二、使用 trait 对象来存储不同类型的值
有这样一个需求
- 创建一个 GUI 工具:
- 它会遍历某个元素的列表,依次调用元素的 draw 方法进行绘制
- 例如:Button、TextField 等元素
- 在面向对象语言里:
- 定义一个 Component 父类,里面定义了 draw 方法
- 定义 Button、TextField 等类,继承与 Component 类
为共有行为定义一个 trait
- Rust 避免将 struct 或 enum 称为对象,因为他们与 impl 块是分开的
- trait 对象有些类似于其它语言中的对象:
- 它们某种程度上组合了数据与行为
- trait 对象与传统对象不同的地方:
- 无法为 trait 对象添加数据
- trait 对象被专门用于抽象某些共有行为,它没其它语言中的对象那么通用
Trait 动态 lib.rs 文件
pub trait Draw { fn draw(&self);}pub struct Screen { pub components: Vec>,}impl Screen { pub fn run(&self) { for component in self.components.iter() { component.draw(); } }}pub struct Button { pub width: u32, pub height: u32, pub label: String,}impl Draw for Button { fn draw(&self) { // 绘制一个按钮 }}
泛型的实现 一次只能实现一个类型
pub struct Screen { pub components: Vec,}impl ScreenwhereT: Draw,{ pub fn run(&self) { for component in self.components.iter() { component.draw() } }}
main.rs 文件
use oo::Draw;use oo::{Button, Screen};struct SelectBox { width: u32, height: u32, options: Vec,}impl Draw for SelectBox { fn draw(&self) { // 绘制一个选择框 }}fn main() { let screen = Screen { components: vec![ Box::new(SelectBox { width: 75, height: 10, options: vec![ String::from("Yes"), String::from("Maybe"), String::from("No"), ], }), Box::new(Button { width: 50, height: 10, label: String::from("OK"), }), ], }; screen.run();}
Trait 对象执行的是动态派发
- 将 trait 约束作用于泛型时,Rust编译器会执行单态化:
- 编译器会为我们用来替换泛型参数的每一个具体类型生成对应函数和方法的非泛型实现。
- 通过单态化生成的代码会执行静态派发(static dispatch),在编译过程中确定调用的具体方法
- 动态派发(dynamic dispatch):
- 无法在编译过程中确定你调用的究竟是哪一种方法
- 编译器会产生额外的代码以便在运行时找出希望调用的方法
- 使用 trait 对象,会执行动态派发:
- 产生运行时开销
- 阻止编译器内联方法代码,使得部分优化操作无法进行
Trait 对象必须保证对象安全
- 只能把满足对象安全(object-safe)的 trait 转化为 trait 对象
- Rust采用一系列规则来判定某个对象是否安全,只需记住两条:
- 方法的返回类型不是 Self
- 方法中不包含任何泛型类型参数
lib.rs 文件
pub trait Draw { fn draw(&self);}pub trait Clone { fn clone(&self) -> Self;}pub struct Screen { pub components: Vec>, // 报错}
三、实现面向对象的设计模式
状态模式
- 状态模式(state pattern)是一种面向对象设计模式:
- 一个值拥有的内部状态由数个状态对象(state object)表达而成,而值的行为则随着内部状态的改变而改变
- 使用状态模式意味着:
- 业务需求变化时,不需要修改持有状态的值的代码,或者使用这个值的代码
- 只需要更新状态对象内部的代码,以便改变其规则,或者增加一些新的状态对象
例子:发布博客的工作流程 main.rs
use blog::Post;fn main() { let mut post = Post::new(); post.add_text("I ate a salad for lunch today"); assert_eq!("", post.content()); post.request_review(); assert_eq!("", post.content()); post.approve(); assert_eq!("I ate a salad for lunch today", post.content());}
lib.rs 文件
pub struct Post { state: Option>, 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 { "" } pub fn request_review(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.request_review()) } } pub fn approve(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.approve()) } }}trait State { fn request_review(self: Box) -> Box; fn approve(self: Box) -> Box;}struct Draft {}impl State for Draft { fn request_review(self: Box) -> Box { Box::new(PendingReview {}) } fn approve(self: Box) -> Box { self }}struct PendingReview {}impl State for PendingRevew { fn request_review(self: Box) -> Box { self } fn approve(self: Box) -> Box { Box::new(Published {}) }}struct Published {}impl State for Published { fn request_review(self: Box) -> Box { self } fn approve(self: Box) -> Box { self }}
修改之后:
pub struct Post { state: Option>, 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()) } } pub fn approve(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.approve()) } }}trait State { fn request_review(self: Box) -> Box; fn approve(self: Box) -> Box; fn content<"a>(&self, post: &"a Post) -> &"a str { "" }}struct Draft {}impl State for Draft { fn request_review(self: Box) -> Box { Box::new(PendingReview {}) } fn approve(self: Box) -> Box { self }}struct PendingReview {}impl State for PendingRevew { fn request_review(self: Box) -> Box { self } fn approve(self: Box) -> Box { Box::new(Published {}) }}struct Published {}impl State for Published { fn request_review(self: Box) -> Box { self } fn approve(self: Box) -> Box { self } fn content<"a>(&self, post: &"a Post) -> &"a str { &post.content }}
状态模式的取舍权衡
- 缺点:
- 某些状态之间是相互耦合的
- 需要重复实现一些逻辑代码
将状态和行为编码为类型
- 将状态编码为不同的类型:
- Rust 类型检查系统会通过编译时错误来阻止用户使用无效的状态
lib.rs 代码:
pub struct Post { content: String,}pub struct DraftPost { content: String,}impl Post { pub fn new() -> DraftPost { DraftPost { content: String::new(), } } pub fn content(&self) -> &str { &self.content }}impl DraftPost { pub fn add_text(&mut self, text: &str) { self.content.push_str(text); } pub fn request_review(self) -> PendingReviewPost { PendingReviewPost { content: self.content, } }}pub struct PendingReviewPost { content: String,}impl PendingReviewPost { pub fn approve(self) -> Post { Post { content: self.content, } }}
main.rs 代码:
use blog::Post;fn main() { let mut post = Post::new(); post.add_text("I ate a salad for lunch today"); let post = post.request_review(); let post = post.approve(); assert_eq!("I ate a salad for lunch today", post.content());}
总结
- Rust 不仅能够实现面向对象的设计模式,还可以支持更多的模式
- 例如:将状态和行为编码为类型
- 面向对象的经典模式并不总是 Rust 编程实践中的最佳选择,因为 Rust具有所有权等其它面向对象语言没有的特性!
标签:
推荐文章
- Rust编程语言入门之Rust的面向对象编程特性
- 智能机器人“小图”让阅读“声”入人心-世界新要闻
- 环球报道:Consul 的安装和配置(二)
- 武汉开展“扣好人生第一粒扣子”主题教育实践活动
- 每日快看:带伞!北京今天有雨,最高气温骤降到15℃
- 年轻时人缘好,生活满意度高
- 环球头条:十七冶濮阳黄河文化艺术中心建设举行开工仪式
- 《灌篮高手》票房破亿,“80后”的青春被唤醒_环球热推荐
- Google将两个AI团队Brain和DeepMind合并成一个
- 高速分组交换技术_关于高速分组交换技术简述-今日播报
- “五一”假期高速公路免费通行 独家焦点
- 中英街管理局开展踏青活动 推动禁毒宣传
- 通讯!门头沟8个新型公共文化空间 丰富市民文化生活
- 常友科技过会:今年IPO过关第95家 海通证券过8单|世界快看
- 五岳之首泰山图片_五岳之首泰山_环球实时
- 当前播报:云南这名医师上榜“中国好医生”
- 面临暴力威胁 美国一地要求学生背透明书包上学|世界最新
- 环球播报:前利雅得新月球员批C罗掏裆:沙特联在这一羞耻行为前岌岌可危
- 丹麦与荷兰将向乌克兰提供14辆“豹2”坦克
- 新华调查|“答非所问”“妨碍维权”……部分“智能客服”不智能现象咋破解?
- 4月20日国内丁苯橡胶市场行情小涨
- 天天热点评!这两类购房补贴可线上申请
- 快讯:LOL:RNG辅助Ming直播爆料夏季赛新中单:“M”开头的四个拼音
- 鼓励民间资本参与重大项目建设 加快落实各项建设条件_全球最新
- 环球看点!八一钢铁:4月20日融资买入574.55万元,融资融券余额1.59亿元
- 世界通讯!经典咏流传曲目_经典咏流传全部曲目
- 哈姆:季后赛不是NCAA锦标赛 输一场并不会被淘汰
- 今热点:科大讯飞:一季度净亏损5785万元,上年同期净利润1.1亿元
- 人民海军成立74周年 海军“战”系列5集报道即将推出
- 青春的含义是什么简答_青春的含义是什么 世界新资讯
- 2023年上海秋季高考时间公布:6月7日至9日举行全国统考
- 中国经济有信心有能力行稳致远_每日资讯
- 增速创10年新低!五大因素压制,2.87万亿企业年金如何扩围?业界呼吁加大税收优惠
- 美股异动 | 九洲大药房(CJJD.US)盘初暴涨超90% 上一交易日大跌超85%
- 今日热门!伊豆的舞女作者_伊豆的舞女txt
- 1比3到5比4!中国00后逆转,轰4连鞭,超级翻袋力阻世界冠军
- 观天下!“护苗”在行动 阅读伴成长
- 违反TikTok禁令,要坐牢20年?美国议员整大活
- 福建古田地震预警误报,成都高新减灾研究所:技术仍需提升
- 舍甫琴科谈05年欧冠决赛:利物浦配得上夺冠,他们比我们更有信念
- 全球快看:中规中矩!范子铭12中5拿下13分4篮板难阻球队失利
- 惠东人才安居房申请条件及申请对象
- 世界微资讯!IMF首席经济学家:世界分裂为竞争集团代价巨大
- 世界新动态:我国科研团队提取出近乎完美的量子纠缠
- 世界资讯:十年后,电动车价格再跌一半?
- 每日速递:五汛镇党建引领助企纾困
- 陕西省大学生足球联赛将于4月26日开幕 赛期24天_全球独家
- 蜂蜜柠檬水放冷冻还是冷藏呢 蜂蜜柠檬水放冷冻还是冷藏呢好喝 环球速读
- 全球快播:深挖天玑9200影像技术实力,全球影像评分发布:OPPO Find X6排名第三!
- 一寸多长cm 一寸多长|快播报
- 招商银行信用卡金卡,招行标准信用卡金卡额度一般多少
- 全球微资讯!大猫为什么不回家(大猫为什么不回家的原因)
- 山西临猗:苹果园新生记
- 天天快资讯丨成都高新芳草街道消费券一人可以领几张2023?
X 关闭
最新资讯
- 个人抵押贷款需要什么条件?满足三个方面就够了,附案例分析
- 环球今头条!仁怀大坝镇优质服务助企纾困解难
- 全球头条:南京二手房挂牌量,涨不动了!
- 世界热讯:海南自贸港交通建设再提速 G98环岛高速公路改建工程一期主体完工
- 电压互感器二次侧为什么不能短路 电压互感器的作用|播报
- 环球今日讯!农民交的350元能买药吗?
- 光大同创今日创业板上市 正式登陆中国资本市场
- 汪峰演唱会现场怎么了?快进来一探究竟-全球球精选
- 天天最新:引领智能化下半场!腾势汽车携N7亮相上海车展
- 新款宝马M3CS拥有542bhp售价115,900英镑|焦点热闻
- 【世界聚看点】博俊科技2023年第一季度净利3443.79万 同比增加95.75% 客户需求增加
- 上海乐高乐园度假区设施服务与行政管理区域已初见规模-焦点快报
- Nymex美原油期货主力日内跌幅达到2.00%,报79.26美元/桶
- 青海“瓜果之乡”民和:人勤春来早“桃花源”里话振兴 天天滚动
- “五一”临近 云南旅游快速升温 速递
- 海报|有一种叫云南的生活 舍不得的丽江_全球新要闻
- 春风动力(603129)4月20日主力资金净卖出447.11万元
- 加速布局新能源赛道 红旗携多款车型亮相上海车展-全球视点
- 子人姓
- 世界快播:唐朝完善三省六部制的影响 三省六部制的影响
- 新资讯:布瑞克:深耕农业互联网,让农民创收百姓获利
- 天宜上佳(688033.SH):约1.1144亿股限售股将于4月26日解禁-全球要闻
- 华宝新能:公司将根据消费者需求 积极研究AI技术在产品中应用
- 济南交警举办“我是小交警”职业体验主题活动
- 站外推广方式有哪些特点_站外推广是什么意思
- 天风证券:给予太平鸟买入评级 环球实时
- 人民币对台币汇率今日汇率查询广州水电医院荔湖 人民币与台帀汇率
- 赌王嫁女经典名场面!百万婚纱、千万场地、上亿嫁妆,鲜花都空运|全球速看料
- 大煞风景!会昌河上的这些油污究竟从哪里来?_新资讯
- 建设类执业资格证书有哪些_执业资格证书有哪些-热文
- 全球实时:DDGS商品报价动态(2023-04-19)
- 不积跬步无以至千里不积小流无以成江海翻译出自_不积跬步无以至千里不积小流无以成江 天天新要闻
- 智能变电站设计技术规定_DL/T5510-2016_对于智能变电站设计技术规定_DL/T5510-2016简单介绍-最新快讯
- 南宁市人事局和社会保障局网_南宁市人事局 全球消息
- 焦点精选!国家发改委:将加快推进充电桩和城市停车设施建设,大力推动新能源汽车下乡
- qq音乐怎么下载mp3格式的歌曲到u盘 怎样在QQ音乐上下载歌曲到U盘
- 天天新消息丨今日美元/日元汇率基本面分析及交易策略(2023年4月19日)
- 【全球新视野】人民银行天津分行:一季度存贷款综合增速9.2%,创2017年9月以来新高
- 4月19日中石化华南乳聚丁苯价格上调
- 【天天报资讯】六旬老兵为烈士守陵42年:我还想再干40年
- 每日热闻!中晶负碳循环经济产业园项目开工奠基仪式圆满举行
- 利润从9亿增长到67亿,前十大股东持股83%,北上资金加仓1.1亿股
- 今热点:吸血蜗牛长什么样子的图片_吸血蜗牛长什么样
- 大行评级 | 瑞银:予安踏目标价137港元 评级“买入”|实时焦点
- set about 和set out_set out set about 有何区别 世界简讯
- 无视反对!美国艾奥瓦州将放宽童工使用限制 延长童工劳动时间_每日快讯
- 新天钢联合特钢接收30辆长征氢能重卡助力环保创A
- 绝了,球迷高喊梅西破防C罗!不雅动作或遭重罚,球王想回欧洲了
- 戴隐形眼镜技巧与注意事项_戴隐形眼镜技巧 每日简讯
- 美国佛罗里达州州长威胁要在迪士尼边上建监狱 微资讯
X 关闭