当前位置: 首页 > news >正文

常州手机网站制作链接搜索引擎

常州手机网站制作,链接搜索引擎,手游游戏源码资源网,人工智能教育培训机构排名喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 17.2.1. 需求 这篇文章以一个例子来介绍如何在Rust中使用trait对象来存储不同值的类型。 …

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

17.2.1. 需求

这篇文章以一个例子来介绍如何在Rust中使用trait对象来存储不同值的类型。

在第 8 章中,我们提到Vector的一个限制是它们只能存储一种类型的元素。我们在 8.2. Vector + Enum的应用 中创建了一个解决方法,其中定义了一个SpreadsheetCell枚举,它具有保存整数、浮点数和文本的变体。这意味着我们可以在每个单元格中存储不同类型的数据,并且仍然有一个代表一行单元格的向量。当我们的可互换项是我们在编译代码时知道的一组固定类型时,这是一个非常好的解决方案。

代码如下:

enum SpreadSheetCell {  Int(i32),  Float(f64),  Text(String),  
}  fn main() {  let row = vec![  SpreadSheetCell::Int(5567),  SpreadSheetCell::Text("up up".to_string()),  SpreadSheetCell::Float(114.514),  ];  
}

然而,有时我们希望我们的库用户能够扩展在特定情况下有效的类型集合,以下是这个例子的需求:

创建一个GUI工具,它会遍历某个元素的列表,依次调用元素的draw方法进行绘制(例如:ButtonTextField等元素)。

这样的需求在面向对象语言里(比如Java或C#)可以定义一个Component父类,里面定义了draw方法。接下来定义ButtonTextField等类,继承于Component这个父类。

上一篇文章中说了Rust并没有提供继承功能,所以想使用Rust来构建GUI工具就得使用其他方法——为共有行为定义一个trait

17.2.2. 为共有行为定义一个trait

首先澄清一些定义:在Rust里我们避免将structenum称为对象,因为它们与impl块是分开的。而trait对象有点类似于其他语言中的对象,因为它们某种程度上组合了数据与行为。

trait对象与传统对象也有不同之处,比如我们无法为trait对象添加数据。

trait对象被专门用于抽象某些共有行为,它没有其他语言中的对象那么通用。

这个GUI工具这么写:

pub trait Draw {fn draw(&self);
}pub struct Screen {pub components: Vec<Box<dyn Draw>>,
}impl Screen {pub fn run(&self) {for component in self.components.iter() {component.draw();}}
}
  • 首先声明了一个公开的trait叫Draw,里面定义了一个方法draw,但没有写具体实现
  • 然后声明了一个公开的结构体叫Screen,它里面有一个公开的字段叫components。它的类型是Vector,里面的元素是Box<dyn Draw>
    Box<>用于定义trait对象,表示Box里的元素实现了Draw trait
  • 通过impl块为Screen写了run方法,一运行就把所有元素画出来

同样是表示某个类型实现某个/某些trait,为什么不适用泛型呢?来看看泛型的写法:

pub trait Draw {fn draw(&self);
}pub struct Screen<T: Draw> {pub components: Vec<T>,
}impl<T> Screen<T>
whereT: Draw,
{pub fn run(&self) {for component in self.components.iter() {component.draw();}}
}

这是因为泛型Vec<T>只要T一固定下来这个Vector里就只能存储这个类型了。举个例子,假如第一个放进这个Vector的元素是Button类型,那么这个Vector的其他元素就只能是Button了(因为Vector里的所有元素类型必须相同)。

而如果是Vec<Box<dyn Draw>>,那么第一个放进去是Button类型,后面还可以放TextField类型,只要是实现了Draw trait的类型都可以放进去。

接下来我们来写实现了Draw trait的类型具体是什么样的:

pub struct Button {pub width: u32,pub height: u32,pub label: String,
}impl Draw for Button {fn draw(&self) {// 绘制按钮}
}
  • 一个Button结构体可能有widthheightlabel字段,所以我们这么定义
  • 通过impl块为Button实现了Draw trait,里面的实际代码就忽略了

这只是lib.rs的内容,接下来到mian.rs写主程序:

use gui::Draw;struct SelectBox {width: u32,height: u32,options: Vec<String>,
}impl Draw for SelectBox {fn draw(&self) {// 绘制一个选择框}
}
  • main.rs里的结构体SelectBox有三个字段,具有 widthheightoptions字段
  • 通过impl块为SelectBox实现了Draw trait,里面的实际代码就忽略了

接着看主函数:

use gui::{Button, Screen};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();
}
  • 主程序里有一个Screen结构体的实例,里面放了SelectBox类型和Button类型(得使用Box::new()封装)。这个Vector能放不同类型的元素正是归功于定义trait对象。
  • 然后调用Screen上的方法run渲染出来即可。实际上run方法不管实际传进去是什么类型,只要这个类型实现了Draw trait即可。

17.2.3. trait对象执行的是动态派发

将trait bound作用于泛型时,Rust编译器会执行单态化:编译器会为我们用来替换泛型参数类型的每一个具体类型生成对应函数和方法的非泛型实现。

这点在 10.2. 泛型 中有阐述:


举个例子:

fn main() {let integer = Some(5);let float = Some(5.0)
}

这里integerOption<i32>floatOption<f64>,在编译的时候编译器会把Option<T>展开为Option_i32Option_f64

enum Option_i32 {Some(i32),None,
}enum Option_f64 {Some(f64),None,
}

也就是把Option<T>这个泛型定义替换为了两个具体类型的定义。

单态后的main函数也变成了这样:

enum Option_i32 {Some(i32),None,
}enum Option_f64 {Some(f64),None,
}fn main(){let integer = Option_i32::Some(5);let float = Option_f64::Some(5.0);
}

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

动态派发(dynamic dispatch) 无法爱编译过程中确定你调用的究竟是哪一种方法,编译器会产生额外的代码以便在运行时找出希望调用的方法。使用trait对象就会执行动态派发,代价是产生一些运行时的开销,并且阻止编译器内联方法代码,使得部分优化操作无法进行。

17.2.4. 使用trait对象必须保证对象安全

只能把满足对象安全(object-safe)的trait转化为trait对象。Rust使用了一系列规则来判定某个对象是否安全,只需要记住两条:

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

看个例子:

pub trait Clone{fn clone(&self) -> self;
}

标准库里Clone trait和clone这个函数的签名如上所示,由于clone方法的返回值是self,所以Clone trait就不符合对象安全。

http://www.yidumall.com/news/99063.html

相关文章:

  • 网站建设与管理课后总结网络营销的特点有哪些?
  • 药膳网站建设的目的seo云优化方法
  • 企业网站的一 二级栏目名称网络营销的特点不包括
  • 网站怎样做支付接口seo技术培训沈阳
  • 建设监理有限责任公司网站快速提高排名
  • 厦门网站建设方案服务青岛网站优化
  • 小精灵网站在线做语文热狗seo外包
  • 网站建设的目的和意义广州网站维护
  • 影响网站权重如何做好一个营销方案
  • 前端开发一般用什么软件seo优化排名服务
  • 怎么用b2b网站做排名全国疫情最新情况公布
  • 东莞南城网站建设公司仿站定制模板建站
  • 绍兴网站建设公司2024近期新闻
  • 国外做宠物用品的网站首页优化排名
  • 吴江网站建设今天国内最新消息
  • 扬州做网站的公司市场营销课程
  • 网站建设设计指标bt磁力搜索
  • 网站上的二维码怎么做哪家公司做seo
  • 网站开发公司 苏州seo是干啥的
  • 专业的网站优化公司排名北京网络推广外包公司排行
  • 电商网站设计系统百度快照推广效果怎样
  • 中国做类似 esty的网站百度网站介绍
  • 建设银行徐州分行网站中山疫情最新消息
  • 微信上开网店怎么开说说seo论坛
  • ueditor 文件大小超出网站限制网络广告的类型有哪些
  • 网站类型广州网站优化系统
  • 苏州做网站费用明细黄金网站app大全
  • flash优秀网站网页开发公司
  • 吉林市城市建设学校网站常德seo快速排名
  • 嘉兴百度网站推广百度公司好进吗