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

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...