2311rust特征

Rust无成本抽象

Rust中抽象基石是trait:
1,TraitRust中唯一的接口概念.多个类型可实现一个特征,事实上,可为现有类型提供新的特征实现.另一方面,想抽象未知类型时,找特征就行了.
2,与C++模板一样,可静态分发特征.
3,可动态分发特征.有时确实需要间接,所以不必运行时"擦除"抽象.想运行时分发时,可使用接口特征.

背景:Rust中的方法

Rust提供了方法自由函数,它们密切相关:

struct Point {x: f64,y: f64,
}
//把(借用的)点转换为串的`自由`函数
fn point_to_string(point: &Point) -> String { ... }
//"固有的`impl"`块,直接在`类型`上定义了可用的方法
impl Point {//此方法在`Point`上都可用,并自动借用`Point`值fn to_string(&self) -> String { ... }
}

上述to_string方法叫"固有"方法,因为它们:
1,(通过impl)绑定到单个具体的"self"类型.
2,在该类型值上自动可用.也即,与函数不同,内置方法总是"在域内".

方法第一个参数总是是显式的"self",根据期望的所有权级别,它是self,&mut self&self.使用.调用方法.
self参数,按方法中使用的self形式隐式借用:

let p = Point { x: 1.2, y: -3.7 };
let s1 = point_to_string(&p);  //显式借用,调用自由函数.
let s2 = p.to_string();        //按`&p`隐式借用,来调用方法

如下,流式生成进程的API:

let child = Command::new("/bin/cat").arg("rusty-ideas.txt").current_dir("/Users/aturon").stdout(Stdio::piped()).spawn();

特征是接口

接口允许每个代码自由切换.对特征,规范主要围绕方法展开.
如,以下用来哈希的简单特征:

trait Hash {fn hash(&self) -> u64;
}

为了为给定类型实现此特征,必须提供匹配签名的哈希方法:

impl Hash for bool {fn hash(&self) -> u64 {if *self { 0 } else { 1 }}
}
impl Hash for i64 {fn hash(&self) -> u64 {*self as u64}
}

Java,C#Scala等语言中的接口不同,可为现有类型实现新特征(如上面的Hash).即可在事后创建抽象,并应用至现有库.

内置方法不同,仅当特征在域时,特征方法才在域中.但是假设Hash在域内,你可编写true.hash(),因此实现一个特征扩展了类型上可用的方法集.
定义和实现特征不过是抽象多个类型满足的通用接口.

静态分发

一般通过泛型消费特征:

fn print_hash<T: Hash>(t: &T) {println!("The hash is {}", t.hash())
}

在未知T类型上,print_hash函数是泛型函数,但要求T实现Hash特征.即可与booli64值一起,使用它:

print_hash(&true);      //实例化`T=bool`
print_hash(&12_i64);    //实例化`T=i64`

静态分发中编译掉泛型.也即,与C++模板一样,编译器生成print_hash方法的两个副本来处理上述代码,每个副本对应一个具体参数类型.

反之表明内部调用t.hash()(实际使用抽象点)的成本为零:按直接静态调用相关实现编译它:

//编译后的代码:直接调用特化`bool`版本
__print_hash_bool(&true);  //
__print_hash_i64(&12_i64);   
//直接调用特化`i64`版本

对像print_hash类函数,该编译模型不是很有用,但对更实际的哈希使用,却非常有用.假设还引入了一个相等比较特征:

trait Eq {fn eq(&self, other: &Self) -> bool;
}

这里按实现trait的类型解析Self的引用;在impl Eq for bool中,它引用bool.
然后,可定义一个在实现哈希EqT类型上是都通用的哈希映射:

struct HashMap<Key: Hash + Eq, Value> { ... }

泛型静态编译模型有几个好处:
1,对具体的KeyValue类型,每次使用HashMap都会产生不同的具体HashMap类型,即HashMap可在其存储桶内联(无间接)布局键和值.
来可节省空间和间接,并提高缓存局部性.

2,HashMap上的每个方法同样会生成特化代码.即,如上,调用哈希Eq,不会产生额外成本.表明优化器可用最具体(也即没有抽象)的代码.
特别是,静态分发允许在泛型用法间内联.
总之,与在C++模板一样,你可用泛型编写无成本的相当高级的抽象.
但是,与C++模板不同的是,会提前完全类型检查特征客户.也即,单独编译HashMap时,会根据抽象HashEq特征检查一次代码类型正确性,而不是在每当应用具体类型时的重复检查.

即库作者可更早,更清晰地出现编译错误,而客户类型检查成本更少(即编译速度更快).

动态分发

有时,抽象不仅是重用或模块化,有时在运行时不能去掉抽象.
如,GUI框架一般涉及响应事件(如点击鼠标)的回调:

trait ClickCallback {fn on_click(&self, x: i64, y: i64);
}

GUI元素,常见的是,允许为单个事件注册多个回调.对泛型,可想象这样写:

struct Button<T: ClickCallback> {listeners: Vec<T>,...
}

但问题立即显现出来:即每个按钮都按ClickCallback一个实现特化,且按钮类型反映了该类型.这不是想要的!

相反,想要一个带一组每个都可能是不同具体类型,但都实现了ClickCallback异构监听器的Button类型.
难点是,如果是一组异构类型,则每个类型都有不同的大小,则如何才能布局内部向量?答案一般是:间接.在向量存储回调指针:

struct Button {listeners: Vec<Box<ClickCallback>>,...
}

在此,就像它是一个类型一样,使用ClickCallback特征.在Rust中,特征类型,但它们是"无大小的",只允许出现在Box(指向堆)或&(可任意指向)等指针后面.

Rust中,像&ClickCallbackBox<ClickCallback>的类型叫"trait对象",它包括指向实现ClickCallbackT类型实例的指针,及一个虚表:一个指向T对trait每个方法实现的指针(这里,只是on_click).
可在运行时用该信息正确分发调用方法,并确保统一表示T.因此,只编译一次Button.

多用途

1,闭包.

类似ClickCallback特征,Rust中的闭包只是特定特征.深入

2,条件API.泛型可有条件地实现特征:

struct Pair<A, B> { first: A, second: B }
impl<A: Hash, B: Hash> Hash for Pair<A, B> {fn hash(&self) -> u64 {self.first.hash() ^ self.second.hash()}
}

在此,仅当组件实现Hash时,Pair类型才实现Hash,但允许在不同环境中使用单个Pair类型,这样最大化支持每个环境API的可用性.

这在Rust中很常见,因此内置了.

#[derive(Hash)]
struct Pair<A, B> { .. }

3,扩展方法.可用Traits使用新方法扩展(在其他地方定义的)现有类型,类似C#的扩展方法.只需在特征中定义新方法,为相关类型提供实现,就可用该方法.

4,标记.Rust有一些"标记类型":发送,同步,复制,调整(Send, Sync, Copy, Sized).这些标记只是带空体的特征,然后可在泛型和特征对象中使用.

可在库中定义标记,它们会自动提供#[derive]风格实现:如,如果所有子类型都是Send,则类型也是.如前,这些标记可能非常强大:发送(Send)标记是Rust保证线安的方式.

5,重载.Rust不支持用多个签名定义相同方法的传统重载.但是trait提供了重载的大部分好处:如果在trait泛型定义了方法,则实现该trait的类型都可调用它.

传统重载相比,有两个优点.首先,即重载不是临时的:一旦理解一个特征,就会立即理解使用它的API重载模式.
其次,它是可扩展的:通过提供新的特征实现,可有效地在方法下游提供新的重载.

6,符号.Rust允许在自己类型上重载+等符号.由相应标准库特征定义每个符号,实现该特征类型也会自动提供符号.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/141956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

比较一个5点的结构对平面的分割

5a61 1 1 0 0 1 0 0 0 1 0 0 1 0 0 1 0 0 计算5a61&#xff0c; 当空间的尺寸是8*8的时候 21 21 5 19 26 26 21 21 21 21 5 19 26 26 21 21 16 16 1 1 8 8 16 16 34 34 14 39 40 1 34 34 34 34 14 39 1 40 34 34 …

LabVIEW中NIGPIB设备与驱动程序不相关的MAX报错

LabVIEW中NIGPIB设备与驱动程序不相关的MAX报错 当插入GPIB-USB设备时&#xff0c;看到了NI MAX中列出该设备&#xff0c;但却显示了黄色警告指示&#xff0c;并且指出Windows没有与您的设备相关的驱动程序。 解决方案 需要安装能兼容的NI-488.2驱动程序。 通过交叉参考以下有…

【C++初阶(八)】C/C++内存管理详解

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

Leetcode刷题详解——不同路径 III

1. 题目链接&#xff1a;980. 不同路径 III 2. 题目描述&#xff1a; 在二维网格 grid 上&#xff0c;有 4 种类型的方格&#xff1a; 1 表示起始方格。且只有一个起始方格。2 表示结束方格&#xff0c;且只有一个结束方格。0 表示我们可以走过的空方格。-1 表示我们无法跨越的…

【读点论文】结构化剪枝

结构化剪枝 在一个神经网络模型中&#xff0c;通常包含卷积层、汇合层、全连接层、非线形层等基本结构&#xff0c;通过这些基本结构的堆叠&#xff0c;最终形成我们所常用的深度神经网络。 早在 1998 年&#xff0c;LeCun 等人使用少数几个基本结构组成 5 层的 LeNet-5 网络&…

Python爬虫过程中DNS解析错误解决策略

在Python爬虫开发中&#xff0c;经常会遇到DNS解析错误&#xff0c;这是一个常见且也令人头疼的问题。DNS解析错误可能会导致爬虫失败&#xff0c;但幸运的是&#xff0c;我们可以采取一些策略来处理这些错误&#xff0c;确保爬虫能够正常运行。本文将介绍什么是DNS解析错误&am…

SpringBoot从零到一项目实战落地博客系统(附源码!!!)

1.项目内容 1.1.页面展示 1.2.博客分类 1.3.面试辅导 1.4.私教带徒 1.5.文章编辑 1.6.后台管理 2.项目架构及技术描述 2.1.本项目用到的技术和框架 项目构建&#xff1a;Mavenweb框架&#xff1a;Springboot数据库ORM&#xff1a;Mybatis数据库连接池&#xff1a; HikariCP分…

[Android]修改应用包名、名称、版本号、Icon以及环境判断和打包

1.修改包名 在Android Studio中更改项目的包名涉及几个步骤&#xff1a; 打开项目结构: 在Android Studio中&#xff0c;确保您处于Android视图模式&#xff08;在左侧面板顶部有一个下拉菜单可以选择&#xff09;。 重命名包名: 在项目视图中&#xff0c;找到您的包名&…

论文导读 | 融合大规模语言模型与知识图谱的推理方法

前 言 大规模语言模型在多种自然语言处理相关任务上展现了惊人的能力&#xff0c;如智能问答等&#xff0c;但是其推理能力尚未充分展现。本文首先介绍大模型进行推理的经典方法&#xff0c;然后进一步介绍知识图谱与大模型融合共同进行推理的工作。 文章一&#xff1a;使用思维…

好消息!2023年汉字小达人市级比赛在线模拟题大更新:4个组卷+11个专项,助力孩子更便捷、有效、有趣地备赛

自从《中文自修》杂志社昨天发通知&#xff0c;官宣了2023年第十届汉字小达人市级比赛的日期和安排后&#xff0c;各路学霸们闻风而动&#xff0c;在自己本就繁忙的日程中又加了一项&#xff1a;备赛汉字小达人市级比赛&#xff0c;11月30日&#xff0c;16点-18点。 根据这几年…

创建符合 Web 可访问性标准的 HTML 布局

人们常说网络可访问性是当今万维网的“必须”。“Web 可访问性”一词定义了开发人员需要遵循的一组准则&#xff0c;以使残障人士和 Web 应用程序的交互更加方便。任何网站的内容、UI/UX 设计和布局都应该易于访问。在本文中&#xff0c;Logicify团队为 HTML/CSS 开发人员提供了…

【开题报告】基于uni-app的高校新生报道APP的设计与实现

1.选题背景和意义 随着高校规模的不断扩大和信息化技术的迅速发展&#xff0c;传统的高校新生报道方式已经无法满足日益增长的新生数量和信息处理的需求。传统的线下报道流程通常存在着信息收集效率低、报到流程繁琐等问题&#xff0c;给学生、教职工和管理人员带来了许多不便…

C 语言指针怎么理解?

今日话题&#xff0c;C 语言指针怎么理解&#xff1f;让我用更简洁的方式来表达这个内容&#xff1a;就像桌面上的快捷方式一样&#xff0c;指针也可以有多层引用。我们可以将指针比作快捷方式的图标&#xff0c;快捷方式可以指向游戏&#xff08;普通指针&#xff09;&#xf…

【JavaEE初阶】IP协议简介

文章目录 前言&#x1f334;IP协议的概念&#x1f333;IP数据报&#x1f6a9;IPv4协议头格式&#x1f6a9;IPv6的诞生 &#x1f38d;IP地址&#x1f6a9;IP地址的格式&#xff1a;&#x1f6a9;IP地址的分类&#x1f388;网络号与主机号的划分 &#x1f6a9;特殊的IP地址&#…

【机器学习】八、规则学习

知识图谱与基本概念 基本概念 规则学习定义&#xff1a;从训练数据中学习出一组能用于对未见示例进行判别的规则。 规则定义&#xff1a;规则一般是&#xff1a;语义明确、能描述数据分布所隐含的客观规律或领域概念。 逻辑规则定义&#xff1a;⊕←?1⋀?2⋀?3…⋀??⊕…

任意注册漏洞

目录 一漏洞介绍 二实战演示 三漏洞修复 本文由掌控安全学院 - 小博 投稿 一漏洞介绍 1.未验证邮箱/手机号 情景&#xff1a;应用为了方便用户记录用户名&#xff0c;使用邮箱和手机号作为用户名&#xff08;因此很多应用在注册的时候就要求用户填写&#xff0c;多数时候…

CTFSHOW -SQL 注入

重新来做一遍 争取不看wp 还是看了。。。。 CTFshow sql注入 上篇(web171-220)更新中 - 掘金 【精选】CTFshow-WEB入门-SQL注入(上)_having盲注_bfengj的博客-CSDN博客 web171 基本联合注入 拿到题目我们已经知道了是sql注入 所以我们可以直接开始 第一题 不会难道哪里去…

软考 系统架构设计师系列知识点之云计算(2)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之云计算&#xff08;1&#xff09; 所属章节&#xff1a; 第11章. 未来信息综合技术 第6节. 云计算和大数据技术概述 3. 云计算的部署形式 根据NIST&#xff08;National Institute of Standards and Technology&…

Pytorch常用的函数(四)深度学习中常见的上采样方法总结

Pytorch常用的函数(四)深度学习中常见的上采样方法总结 我们知道在深度学习中下采样的方式比较常用的有两种&#xff1a; 池化 步长为2的卷积 而在上采样过程中常用的方式有三种&#xff1a; 插值 反池化 反卷积 不论是语义分割、目标检测还是三维重建等模型&#xff0…