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

Rust泛型Generics

泛型

泛型(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程序设计语言

相关文章:

Rust泛型Generics

泛型 泛型&#xff08;Generics&#xff09;是一种程序设计风格&#xff0c;它允许程序员在强类型语言&#xff08;例如rust&#xff0c;c#&#xff0c;c&#xff09;中编写代码时使用通用类型。以rust为例&#xff0c;如果你想实现一个通用的add函数&#xff0c;让其在u8, i3…...

六、并发集合

文章目录并发集合ConcurrentHashMap存储结构存储操作put方法putVal方法-散列算法putVal方法-添加数据到数组&初始化数组putVal方法-添加数据到链表扩容操作treeifyBin方法触发扩容tryPreSize方法-针对putAll的初始化操作tryPreSize方法-计算扩容戳并且查看BUGtryPreSize方法…...

PHY调试经验

1. PHY调试过程 1.设备树中配置正确的PHY ADDR、PHY ID、clause 45或者22协议&#xff0c;PHY ADDR配置不正确会导致MDC/MDIO通信不正常或失败&#xff0c;PHY ID用于匹配PHY驱动程序。 2.通过MDC/MDIO读写PHY ID并对比datasheet中的PHY ID&#xff0c;确认MDC/MDIO通信是否正常…...

从Java培训班出来好找工作吗?

个人觉得这个问题要从两方面来看&#xff0c;首先是培训班的Java课程质量如何&#xff0c;是否贴合用人单位实际需求&#xff0c;学出来的技术能对口&#xff1b;其次是培训班是否保障就业&#xff0c;有就业机会渠道推荐&#xff0c;比如老学员内推、合作企业人才输送以及企业…...

第51天|LeetCode503.下一个更大元素 II、LeetCode42. 接雨水

1.题目链接&#xff1a;下一个更大元素 II 题目描述&#xff1a; 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元素 是按数组遍历顺序&#…...

[12]云计算概念、技术与架构Thomas Erl-第5章 云使能技术

目录 第五章 云使能技术 5.1宽带网络和Internet架构 5.1.1Internet服务提供者&#xff08;ISP&#xff09; 5.1.2无连接分组&#xff08;数据报网络&#xff09; 5.1.3基于路由器的互联 5.1.4技术和商业考量 总结 5.2数据中心技术 5.2.1虚拟化 5.2.2标准化与模块化 …...

超实用的公众号用户运营方案分享,纯干货

公众运营是以用户为主的&#xff1a; 但是你知道什么是用户运营吗&#xff1f;你的公众号有没有维护好目标用户群体呢&#xff1f;你知道该怎么分析你的公众号用户群体吗&#xff1f;你知道分析完之后具体应该怎么做用户运营吗&#xff1f; 接下来伯乐网络传媒就来给大家分享…...

Git ---- 国内代码托管中心-码云

Git ---- 国内代码托管中心-码云1. 简介2. 码云账号注册和登录3. 码云创建远程仓库4. IDEA 集成码云1. IDEA 安装码云插件2. IDEA 连接码云5. 码云复制 GitHub 项目1. 简介 众所周知&#xff0c;GitHub 服务器在国外&#xff0c;使用 GitHub 作为项目托管网站&#xff0c;如果…...

【学习笔记】NOIP爆零赛8

trash ,但不完全是trash t1t1t1考了一个神奇的结论还没有证明&#xff0c;t2t2t2玩了一些复杂度的花样&#xff0c;t3t3t3稍微阳间一点&#xff0c;是一个并不复杂的容斥&#xff0c;如果放在t1t1t1可能更合适一些&#xff0c;t4t4t4就是在原题的基础上改了一下然后就成了一道毒…...

【Linux驱动】驱动设计硬件基础----串口、I2C、SPI、以太网接口、PCIE

1.前言 常见的外设接口与总线的工作方式&#xff0c;包括串口、I2C、SPI、USB、以太网接口、PCI和PCI-E、SD和SDIO等。 2.串口 RS-232、RS-422与RS-485都是串行数据接口标准&#xff0c;最初都是由电子工业协会&#xff08;EIA&#xff09;制订并发布的。 3.I2C I2C&…...

同为(TOWE)防雷产品助力福建移动南平分公司防雷改造

01 公司简介中国移动通信集团福建有限公司南平分公司属于福建移动地级分公司&#xff0c;所属行业为电信、广播电视和卫星传输服务。现已建成覆盖范围广、业务品种多、通信质量高的综合通信网络&#xff0c;具备行业领先的经营管理制度。移动通信大楼的综合防雷及地接系统&…...

Win10安装mediapipe的步骤

我之前想自己安装mediapipe包进行人体检测的学习&#xff0c;但整了好几个月都不行&#xff0c;这次终于让我整好了&#xff0c;我的python版本为python 3.7.1。注意&#xff0c;不要直接用pip install mediapipe 进行安装&#xff0c;我之前这样安装的&#xff0c;mediapipe安…...

项目调研丨以太坊再质押项目EigenLayer白皮书四大看点(内附完整版中文白皮书)

北京时间2月21日下午&#xff0c;被众多一线投研机构视为2023年以太坊最重要的创新&#xff0c;有可能开启以太坊新叙事方向的项目Eigenlayer终于披露了其第一版白皮书。EigenLayer是以太坊的再质押集&#xff0c;允许共识层ETH质押者选择验证构建在以太坊生态系统之上的新软件…...

51-Jenkins-Periodic Backup插件实现Jenkins备份

Periodic Backup插件实现Jenkins备份前言目录结构插件备份安装插件使用插件前言 本篇来学习下使用Periodic Backup插件实现Jenkins备份 目录结构 Jenkins的所有数据都是存放在文件中的&#xff0c;所以&#xff0c;Jenins备份其实就是备份Jenkins_HOME目录。 Jenkins_Home目…...

C++之入门之引用,内联函数

一、引用 1、引用的概念 在C中&#xff0c;引用的本质其实就是给一个已经存在的变量”起别名“。也就是说&#xff0c;引用与它所引用的对象共用一块空间。&#xff08;同一块空间的多个名字&#xff09; 就比如说&#xff0c;李逵又叫黑旋风&#xff0c;而黑旋风就是指李逵…...

linux kprobe使用

使用场景 监控某个内核函数是否被调用获取某个内核函数耗费的时间获取某个内核函数的入参获取某个内核函数的调用栈&#xff08;dump_stack()&#xff09;获取某个内核函数的返回值 参数传递规则 x86平台对pt_regs的定义 arch/x86/include/asm/ptrace.h // i386架构 #ifdef…...

2023年超全前端面试题-背完稳稳拿offer(欢迎补充)

HTML、CSS相关 HTML5 HTML5新特性 增强了表单&#xff0c;input新增了一些type&#xff1a; color----定义调色板 tel-----定义包含电话号码的输入域 email—定义包含email地址的输入域 search–定义搜索域 number–定义包含数值的输入域 date----定义选取日、月、年的输入域…...

python之web自动化测试框架

梳理下搭建web自动化框架的流程&#xff1a; 创建目录&#xff1a; cases&#xff1a;存放测试用例&#xff0c;unittest框架要求用例名必须以test开头&#xff0c;所以命名test_case.py test_case.py代码如下&#xff1a;继承unittest.TestCase类下面的方法setupclass(),te…...

算法笔记(十五)—— 动态规划(暴力递归到动态规划)习题训练!

通过递归到记忆化搜索再到严格表结构的动态规划 递归方法的评价&#xff1a;1. 单可变参数的维度&#xff1b;2. 可变参数的个数 记忆化搜索 在暴力递归中会存在很多的重复计算&#xff0c;可以使用存储结构来实现空间换时间。 严格表结构的动态规划 整理位置之间的依赖关系…...

云原生架构基础概念及应用办法

什么是云原生&#xff1f; 云原生是一种基于容器、微服务和自动化运维的软件开发和部署方法。它可以使应用程序更加高效、可靠和可扩展&#xff0c;适用于各种不同的云平台。 如果要更直接通俗的来解释下上面的概念。 云原生更准确来说就是一种文化&#xff0c;是一种潮流&a…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...