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

个人网站与企业网站区别手机版oa系统

个人网站与企业网站区别,手机版oa系统,导航网站链接怎么做,wordpress仿站标签喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 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.hyszgw.com/news/36516.html

相关文章:

  • 网站建设网站制作公司saas自助建站
  • wordpress博客导航开源主题qq关键词排名优化
  • 婚纱设计网站首页做网站做得好的公司有哪些
  • 苏州高端网站设计制作手机网站如何做
  • 汤唯梁朝伟做视频网站win10最强优化软件
  • 网站 推广方案网站建设html
  • 能答题做试卷的网站做校园文化展览的网站
  • 上海的设计网站有哪些婚嫁行业网站模板
  • 网站备案 教程google安卓手机下载
  • 上海服装品牌网站建设电商运营培训机构
  • linux下网站开发不想用原来的网站模板了就用小偷工具采集了一个可是怎么替换
  • 网站空间容量怎么让网站排名下降
  • 硬盘做免费嗳暧视频网站全网营销心得体会
  • 网站建设维护与管理实训总结wordpress 赚钱
  • 网站建设的意义怎么写六年级做的网站的软件下载
  • 网站流量查询网站专项审批查询
  • 网站轮播图制作2345网址导航浏览器下载安装
  • photoshop画简单网站宁波商城网站建设
  • 做网站需要注意的建设网站模块需要哪些内容
  • 百度地图网站开发健康管理公司网站建设
  • 外贸网站注册企查查官网查企业
  • 侯马做网站网站建设与管理课程标准
  • 上海城乡住房建设部网站首页免费追漫软件app
  • 英语网站推广策划书设置网站语言
  • 如何建网站运营网站网站美工难做吗
  • 被墙域名黑别人网站微信公众平台网页制作
  • 云南省玉溪市建设局官方网站泰州网站建设与网页制作
  • 搭建网站的方案免费虚拟房屋设计软件
  • 自己可以做企业网站吗wordpress友链图标
  • 网站建设价格怎么算电商网站的分辨率