Rust泛型Generics

news/2024/4/19 17:38:25/文章来源:https://blog.csdn.net/zy010101/article/details/129244466

泛型

泛型(Generics)是一种程序设计风格,它允许程序员在强类型语言(例如rust,c#,c++)中编写代码时使用通用类型。以rust为例,如果你想实现一个通用的add函数,让其在u8, i32, u64等类型中通用。如果没有泛型,虽然它们的逻辑是一致的,但是你需要为不同类型编写不同的函数,而泛型帮助我们只需要编写一个函数,实现通用逻辑即可。例如:

fn main() {println!("{}", add(1u8, 2u8));println!("{}", add(1i32, 2i32));println!("{}", add(1f32, 2f32));
}fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {a + b
}

执行这段代码,输出结果如下所示:

3
3
3

可以看到这段代码成功执行,add函数接受多种类型的参数,帮我们减少了代码的编写。泛型是rust多态能力的一种体现。在动态语言中,调用方法一般不受类型约束,称其为“鸭子类型”。也就是说一个东西看起来像鸭子,叫起来像鸭子,游起来也像鸭子,那就认为它就是鸭子。

泛型是一个非常强大的工具,但是如何合理的使用它才是问题。在C/C++和Rust里,掌握泛型对于程序员而言是比较困难的一点。(例如泛型的编译错误有时候很难通过编译器的报错信息进行修正)

上面代码的 T 就是泛型参数,实际上在 Rust 中,泛型参数的名称你可以任意起,但是出于惯例,我们都用 T ( T 是 type 的首字母)来作为首选,这个名称越短越好,除非需要表达含义,否则一个字母是最完美的。

使用泛型参数,有一个先决条件,必需在使用前对其进行声明。

fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T

这个add函数的定义可以这样理解,函数名后面的T是泛型类型,我们在后面的函数参数以及返回值使用了该类型,因此必须在使用前对其进行声明。而std::ops::Add<Output = T>是对泛型的约束。因为不是所有的T类型都可以进行+运算符操作。
上面的示例展示了rust中的函数泛型,下文将介绍rust中各种各样的泛型。

结构体中使用泛型

结构体中的字段类型也可以用泛型来定义。例如:

struct Point<T> {x: T,y: T,
}fn main() {let integer = Point { x: 5, y: 10 };let float = Point { x: 1.0, y: 4.0 };
}

和前面的函数中使用泛型类似,我们依旧需要注意两个点。

  1. 提前声明,在使用泛型类型之前必需要进行声明 Point<T>,接着就可以在结构体的字段类型中使用 T 来替代具体的类型。
  2. x 和 y 是相同的类型,它们都是类型T。

枚举中使用泛型

在Rust中,枚举中很典型的泛型有Option和Results。Option这个枚举类型用来判断一个数据是有值;而Results则是用来判断值是否正确。它们的定义如下所示:

enum Option<T> {Some(T),None,
}enum Result<T, E> {Ok(T),Err(E),
}

Result中的泛型类型有两个,分别是T和E。泛型类型可以有多个,但是如果太过复杂,例如<T, U, V, W, X, Y, Z>这种包含超过5种泛型类型的,此时最后考虑将其进行拆分。

方法中使用泛型

一开始的示例是在函数中使用泛型,现在我们来看一下如何在方法中使用泛型。实际上和函数中使用类似。例如:

#![allow(unused)]
struct Point<T> {x: T,y: T,
}// 提前声明泛型类型T,由于是对泛型结构体Point实现的方法。因此结构体的名称应该是Point<T>
impl<T> Point<T> {// 由于在impl处已经提前声明了泛型T,因此在方法中不用再次声明了。fn x(&self) -> &T {&self.x}// 由于在impl处已经提前声明了泛型T,因此在关联函数中不用再次声明了。fn new(x:T, y:T) -> Point<T> {Point { x, y }}
}fn main() {let p = Point { x: 5, y: 10 };let q = Point::new(123.123, 456.456);println!("p.x = {}", p.x());println!("q.x = {}", q.x());
}

使用泛型参数前,依然需要提前声明:impl<T>

多个泛型参数

泛型类型可以有多个,下面是一个例子:

#[derive(Debug)]
struct Point<U, V>{x: U,y: V,
}impl<U, V> Point<U, V> {fn new(x:U, y: V) -> Point<U, V> {Point { x, y}}// X, Y这两个泛型类型不属于Point<U, V>的方法实现,因此不能写在impl后面,而是需要写在swap后面。// swap的两个参数都不是引用,会引起所有权的转移fn swap<X, Y>(self, p:Point<X, Y>) -> Point<U, Y> {Point {x: self.x, y: p.y}}
}fn main() {let p1 = Point::new(1, "2");let p2 = Point::new(3.0f32, 4.5);let p3 = p1.swap(p2);println!("{:?}", p3);}

结构体可以有多个泛型类型,方法和关联函数等也可以拥有多个泛型类型。需要注意的是,swap函数的写法,因为X, Y这两个泛型类型不属于Point<U, V>的方法实现,因此不能写在impl后面,而是需要写在swap后面。

泛型性能

Rust 通过在编译时进行泛型代码的 单态化(monomorphization)来保证效率。单态化是一个通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。

这个过程中,编译器所做的工作正好与我们在代码中所做的工作相反,编译器寻找所有泛型代码被调用的位置并使用泛型代码针对具体类型生成代码。

在编译时就确定的多态,势必会导致编译时间变长,但是它带来的好处则是代码执行时速度的提高;而Trait则可以带来运行时的多态,实现原理类似于C++的虚表,虚指针。

参考资料

  1. Rust语言圣经
  2. Rust程序设计语言

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

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

相关文章

文献阅读笔记 # 面向大规模多版本软件系统的代码克隆检测加速技术

面向大规模多版本软件系统的代码克隆检测加速技术&#xff0c;方维康 吴毅坚 赵文耘&#xff0c;《计算机应用与软件》复旦大学软件学院、复旦大学上海市数据科学重点实验室2022 April 面向大规模多版本软件系统的代码克隆检测加速技术 摘要 很多代码克隆检测方法主要针对软…

【博学谷学习记录】超强总结,用心分享丨人工智能 多场景实战 常用英文缩写概念总结

目录PV(Page View)UV(Unique Visitor)CPM(Cost Per Mille)CPC(Cost Per Click)CPA(Cost Per Action)CPI(Cost Per Install)ACU(Average concurrent users)PCU(Peak concurrent users)ARPU(Average Revenue Per User)ARPPU(Average Revenue Per Paying User)LTV(Life Time Value…

Linux命令之lz4命令

一、lz4命令简介 LZ4是一种压缩格式&#xff0c;特点是压缩/解压缩速度超快(压缩率不如gzip)&#xff0c;如果你特别在意压缩速度&#xff0c;或者当前环境的CPU资源紧缺&#xff0c;可以考虑这种格式。lz4是一种非常快速的无损压缩算法&#xff0c;基于字节对齐LZ77系列压缩方…

西电计算机通信与网络(计网)简答题计算题核心考点汇总(期末真题+核心考点)

文章目录前言一、简答计算题真题概览二、网桥&#xff0c;交换机和路由器三、ARQ协议四、曼彻斯特编码和差分曼彻斯特编码五、CRC六、ARP协议七、LAN相关协议计算前言 主要针对西安电子科技大学《计算机通信与网络》的核心考点进行汇总&#xff0c;包含总共26章的核心简答。 【…

【Linux】Linux根文件系统扩容

场景&#xff1a;根文件系统需要至少100GB的剩余空间&#xff0c;但是目前就剩余91GB。因此&#xff0c;我们需要对根文件系统进行扩容。# df -h 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 3.9G 0 3.9G 0% /dev tmpfs …

密码暴力破解

密码的暴力破解准备工具功能简介Burp Intruder工作原理Intruder应用场景爆破实操准备工具 首先准备好BurpSuite和Dvwa作为测试工具和实验对象。 功能简介 Burp Intruder工作原理 Intruder在原始请求数据的基础上&#xff0c;通过修改各种请求参数&#xff0c;以获取不同的请…

flutter 微信聊天输入框

高仿微信聊天输入框&#xff0c;效果图如下&#xff08;目前都是静态展示&#xff0c;服务还没开始开发&#xff09;&#xff1a; 大家如果观察仔细的话 应该会发现&#xff0c;他输入框下面的高度 刚好就是 软键盘的高度&#xff1b;所以在这里就需要监听软键盘的高度。还要配…

Hbase资源隔离操作指南

1.检查集群的环境配置 1.1 HBase版本号确认> 5.11.0 引入rsgroup的Patch&#xff1a; [HBASE-6721] RegionServer Group based Assignment - ASF JIRA RegionServer Group based Assignment 社区支持版本&#xff1a;2.0.0 引入rsgroup的CDH版本 5.11.0 https://www.…

购买运动耳机应该考虑什么问题、运动达人必备的爆款运动耳机

喜欢运动的小伙伴都知道&#xff0c;运动和音乐是最配的&#xff0c;在运动中伴随着节奏感的音乐能够让自己更兴奋&#xff0c;锻炼的更加起劲儿。在运动耳机方面我也一直都有所研究&#xff0c;购买运动耳机最重要的就是要满足我们运动时候听音乐的需求&#xff0c;从佩戴舒适…

《C++ Primer Plus》(第6版)第5章编程练习

《C Primer Plus》&#xff08;第6版&#xff09;第5章编程练习《C Primer Plus》&#xff08;第6版&#xff09;第5章编程练习1. 计算闭区间内的整数和2. 重新编写程序清单5.43. 累加4. 投资价值5. 销售情况6. 销售情况27. 汽车8. 销售情况29. 销售情况210. 销售情况2《C Prim…

【技术美术图形部分】简述主流及新的抗锯齿技术

电脑的世界里没有曲线&#xff0c;都是三角面组成一个个模型的&#xff0c;因此一定会出现走样&#xff08;锯齿&#xff09;的情况&#xff0c;只是严重与否的问题&#xff0c;而AA也是实时渲染最难解决的问题之一。 Sampling&Artifacts Lecture 06 Rasterization 2 (An…

MAML算法详解(元学习)

文章目录回顾元学习MAML算法MAML和预训练模型的区别数学推导MAML实施细节总结回顾元学习 元学习的基本知识参考这篇博客元学习和机器学习的对比 MAML算法 学习初始化参数&#xff0c;所有任务的初始化的参数都是一样的 MAML和预训练模型的区别 MAML使用的是ϕ\phiϕ…

阶段十:总结专题(第六章:缓存篇)

阶段十&#xff1a;总结专题&#xff08;第六章&#xff1a;缓存篇&#xff09;Day-第六章&#xff1a;缓存篇1. Redis 数据类型**String****List****Hash****Sorted Set**2. keys 命令问题3. 过期 key 的删除策略4. Redis 持久化**AOF 持久化****AOF 重写****RDB 持久化****混…

Python 中 openpyxl 模块封装,读写 Excel 文件中自动化测试用例数据

只有测试数据和错误提示信息不同&#xff0c;其他代码都是一样的&#xff0c;不这样不易修改数据和维护&#xff0c;会有两点痛点 1.代码冗余极其严重, 程序可读性不佳 2.程序拓展性很差 往往我们在自动化测试汇总&#xff0c;会将数据放在 Excel 文件、CSV文件、数据库 Py…

Python-scatter散点图及颜色大全

# -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as pltplt.rcParams[font.sans-serif][SimHei] plt.rcParams[axes.unicode_minus] False #matplotlib画图中中文显示会有问题&#xff0c;需要这两行设置默认字体plt.xlabel(X) plt.ylabel(Y) plt.xlim…

【IP技术】ipv4和ipv6是什么?

IPv4和IPv6是两种互联网协议&#xff0c;用于在互联网上标识和寻址设备。IPv4&#xff08;Internet Protocol version 4&#xff09;是互联网协议的第四个版本&#xff0c;是当前广泛使用的互联网协议。IPv4地址由32位二进制数构成&#xff0c;通常表示为4个十进制数&#xff0…

大数据技术之Hive(四)分区表和分桶表、文件格式和压缩

一、分区表和分桶表1.1 分区表partitionhive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录&#xff0c;每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择式选择查询所需要的分区&#xff0c;这样的查询效率辉提高很多。1.1.1 分区表基本语…

2023年蜂巢科技最新面试题

2023年蜂巢科技最新面试题 bio与nio的区别 bio同步阻塞io&#xff1a;在此种⽅式下&#xff0c;⽤户进程在发起⼀个IO操作以后&#xff0c;必须等待IO操作的完成&#xff0c;只有当真正完成了IO操作以后&#xff0c;⽤户进程才能运⾏。JAVA传统的IO模型属于此种⽅式&#xff0…

flink常用算子介绍

flink任务中【Transformation 数据转换】是对数据进行操作&#xff0c;有 Map、FlatMap、Filter、KeyBy 、Reduce 、Fold 、Aggregations、Window 、WindowAll 、Union 、Window join 、Split 、Select 、Project 等&#xff0c;通过对数据的操作&#xff0c;转换成想要的数据&…

HttpRunnerManager部署

基于HttpRunner的接口自动化测试平台: HttpRunner, djcelery and Django_. HttpRunner手册: http://cn.httprunner.org/git地址&#xff1a;httprunner/HttpRunnerManager: 基于 HttpRunner 的 Web 测试平台&#xff0c;已停止维护。 (github.com)部署机器&#xff1a;linux部署…