当前位置: 首页 > 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…...

RedisTemplate 的基本使用手把手教

下载实例源码 使用步骤 1、引入 spring-boot-starter-data-redis 依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency>2、在 application.yml 配置 R…...

Hbase -- Compact工具梳理

1. 背景 当前&#xff0c;线上HBase集群的自动Major Compact是关闭的&#xff0c;我们选择在凌晨业务空闲的时候进行手动触发Major Compact&#xff0c;Compact工具就是在运维平台上对资源组、RS、表进行Major Compact。目前线上有2种版本的Compact程序&#xff1a;Compact_v1…...

【java代码审计】SQL注入

1 原理 没有正确的对用户的输入进行检查&#xff0c;将用户的输入以拼接的方式带入到SQL语句中&#xff0c;导致SQL注入。 2 产生SQL注入的原因 2.1 JDBC拼接不当造成SQL注入 前置知识&#xff1a; JDBC执行SQL语句的两种方式&#xff1a; PrepareStatement&#xff1a;会对…...

前置知识-辛 Runge-Kutta 方法

1.3.3 辛 Runge-Kutta 方法 将方程 ( 1.10.2 ) (1.10 .2) (1.10.2) 改写为 d z d x =...

require 与 import 两种引入模块方式到底有什么区别?

关于JavaScript 的模块化规范&#xff0c;可以移步至&#xff1a; 【JavaScript高级】模块化规范「一文让你彻底搞懂前端模块化规范 & 区别」 下面进入正题 require 与 import 两种引入模块方式&#xff0c;到底有什么区别呢&#xff1f; 大致可以分为以下几个方面&#…...

软考信息系统监理师备考建议

用好备考方法&#xff0c;两三个月就可以过的。信息系统监理师备考最好以教材和历年真题为主&#xff0c;教学视频模拟题为辅。考试介绍与复习建议&#xff1a;考试设置的科目包括&#xff1a;&#xff08;1&#xff09;信息系统工程监理基础知识&#xff0c;考试时间150分钟&a…...

第八届蓝桥杯省赛——4承压计算(二维数组,嵌套循环)

题目&#xff1a;X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。每块金属原料的外形、尺寸完全一致&#xff0c;但重量不同。金属材料被严格地堆放成金字塔形。7 5 8 7 8 8 9 2 7 2 8 1 4 9 1 8 1 8 8 4 1 7 9 6 1 4 5 4 5 6 5 5 6 9 5 6 5 5 4 7 9 3 5 5 1 7 5 7 9 7 4…...

【ECNU】3645. 莫干山奇遇(C++)

目录 题目 输入格式 输出格式 样例 提示 思路 代码 题目 单点时限: 2.0 sec 内存限制: 512 MB 出题人当然是希望出的题目有关 oxx&#xff0c;于是想方设法给题目配上一些有关 oxx 的背景故事&#xff0c;使得它看起来不那么无趣。但有的时候却无法引入合适的小姐姐&…...

为什么需要学习shell、shell的作用

课程基于B站于超课程笔记 03 Shebang的正确玩法_哔哩哔哩_bilibili P1 shell的作用 P2 shell执行命令的流程 P3 Shebang的正确玩法 什么是shell及组成 shell概念 shelll组成 Shebang概念 /bin/sh /bin/bash一样&#xff0c;都是指向一个bash解释器 [rootlocalhost ~]#…...

pgsql-Create_ALTER_GRANT_REVOKE命令语法

pgsql-Create_ALTER_GRANT_REVOKE命令语法 资料 语法约定 CREATE ROLE ALTER ROLE GRANT授权 REVOKE回收授权 权限类型说明 语法约定 下面的约定被用于命令的大纲&#xff1a;方括弧&#xff08;[和]&#xff09;表示可选的部分&#xff08;在 Tcl 命令里&#xff0c;使…...

贵港网站建设公司/seo报价单

v-bind 有三种修饰符&#xff0c;分别为 .sync、.once、.camel。.sync : 用于组件props属性&#xff0c;进行双向绑定&#xff0c;即父组件绑定传递给子组件的值&#xff0c;无论在哪个组件中对其进行了修改&#xff0c;其他组件中的这个值也会随之更新。案例背景爸爸给儿子钱&…...

wordpress构建/个人网站设计内容

1 、标量类型声明 有两种模式 : 强制 ( 默认 ) 和 严格模式。 现在可以使用下列类型参数&#xff08;无论用强制模式还是严格模式&#xff09;&#xff1a; 字符串 (string), 整数 (int), 浮点数 (float), 以及布尔值 (bool) 。它们扩充了 PHP5 中引入的其他类型&#xff1a;类…...

温州网站设计服务商/黄页网

Firebug的Console API 每个用Firefox加载的页面&#xff0c;Firebug都添加了一个全局变量console&#xff0c;通过这个变量的若干方法&#xff0c;你可以通过脚本向控制台输出各种调试信息。 console.log(object[, object, ...]) 往控制台写一条信息&#xff0c;可以有多个参数…...

景安怎么把网站做别名/网站seo基础优化

在5月20日结束的2021深度学习开发者峰会 WAVE SUMMIT 上&#xff0c;百度文心 ERNIE 开源了四大预训练模型。本文对这四大开源预训练模型进行了详细的技术解读。 2019年以来&#xff0c;NLP 预训练模型在技术创新和工业应用上不断取得突破&#xff0c;但当前预训练模型仍有一些…...

哪个网站可以做微信引导图/北京网站建设公司案例

Nginx概览 一款轻量级WEB服务器、也是一款反向代理服务器 作用&#xff1a;1.可直接支持Rails和PHP的程序 2.可作为HTTP反向代理服务器 3.作为负载均衡服务器 4.作为邮件代理服务器 5.帮助实现前端动静分离 特点&#xff1a;高稳…...

macbook air做网站/2023年6月份疫情严重吗

PagerAdapter的方法getCount() 获取viewpager中有多少view instantiateItem() 1.将给定的view添加到viewGroup&#xff08;容器&#xff09;中&#xff0c;创建并显示出来 2.返回一个代表新增页面的object&#xff08;key&#xff09;,通常都是直接返回view本身就可以了&…...