详解Rust泛型用法
文章目录
- 基础语法
- 泛型与结构体
- 泛型约束
- 泛型与生命周期
- 泛型与枚举
- 泛型和Vec
- 静态泛型(const 泛型)
- 类型别名
- 默认类型参数
- Sized Trait与泛型
- 常量函数与泛型
- 泛型的性能
Rust是一种系统编程语言,它拥有强大的泛型支持,泛型是Rust中用于实现代码复用和类型安全的重要特性。通过泛型程序员可以编写能够操作不同类型数据的函数、结构体、枚举和方法,同时又能确保类型安全,避免类型错误。在Rust中泛型的使用不仅能够提升代码的复用性,还能使得代码更加灵活,尤其是在实现与数据类型无关的算法时。
泛型的关键特点:
1.通过类型占位符(如 T)使得代码能够与多种类型一起工作。
2.Rust会在编译时检查类型,保证类型一致性。
3.通过泛型,我们可以在不牺牲类型安全的前提下编写通用代码。
基础语法
Rust泛型的基础语法是使用尖括号<>来指定类型的占位符。
fn print_value<T>(value: T) {println!("{:?}", value);
}fn main() {print_value(42); // T 由 i32 类型替代print_value("Hello, Rust!"); // T 由 &str 类型替代
}
在上面的代码中print_value函数接受一个类型为T的参数value并打印它的值。这里T是一个泛型类型,在main函数中分别传入了i32和&str类型。
泛型与结构体
Rust中的结构体也可以使用泛型,这使得我们能够定义更加通用的容器结构体。泛型结构体允许我们在实例化时为结构体的字段指定具体的类型。
struct Point<T> {x: T,y: T,
}impl<T> Point<T> {fn new(x: T, y: T) -> Self {Point { x, y }}fn get_x(&self) -> &T {&self.x}fn get_y(&self) -> &T {&self.y}
}fn main() {let p1 = Point::new(1, 2); //T由i32类型替代let p2 = Point::new(1.1, 2.2); //T由f64类型替代println!("p1: ({}, {})", p1.get_x(), p1.get_y());println!("p2: ({}, {})", p2.get_x(), p2.get_y());
}//两个参数可以类型不同
struct Point<T,U> {x: T,y: U,
}
fn main() {let p = Point{x: 1, y :1.1};
}
泛型约束
泛型本身并不限制类型的行为,但在某些情况下我们希望限制泛型类型的行为或特性。为此Rust引入了泛型约束(Traits)。通过where关键字或者impl块中的trait约束,可以确保泛型类型实现了某些特定的行为。
use std::fmt::Debug;fn print_debug<T: Debug>(value: T) {println!("{:?}", value);
}fn main() {print_debug(42); //适用于实现了Debug的i32类型print_debug("Hello, Rust!"); //适用于实现了Debug的&str类型
}
除了在函数签名中使用T: Trait语法外,Rust还允许通过where语法进行更复杂的泛型约束。
fn print_debug<T>(value: T)
whereT: Debug,
{println!("{:?}", value);
}
泛型与生命周期
Rust的生命周期(lifetimes)和泛型是密切相关的。为了保证内存安全,Rust强制要求你显式标注引用类型的生命周期。这使得在处理泛型类型时,生命周期标注变得尤为重要。生命周期的内容在后面的文章中会详细介绍,这里就不细说了。
//生命周期 'a 确保了返回的引用在两个输入字符串的生命周期内有效
fn longest<'a, T>(s1: &'a str, s2: &'a str) -> &'a str {if s1.len() > s2.len() {s1} else {s2}
}fn main() {let string1 = String::from("long string");let string2 = String::from("short");let result = longest(&string1, &string2);println!("The longest string is: {}", result);
}
泛型与枚举
Rust的枚举也可以使用泛型,这使得我们可以定义更灵活和强大的枚举类型。比如,Option 和 Result<T, E> 就是标准库中的泛型枚举类型。
//Option 用于值的存在与否不同,Result 关注的主要是值的正确性
enum Option<T> {Some(T),None,
}
enum Result<T, E> {Ok(T),Err(E),
}fn main() {let some_value = Option::Some(42);let none_value: Option<i32> = Option::None;match some_value {Option::Some(value) => println!("Some value: {}", value),Option::None => println!("No value"),}
}
泛型和Vec
Rust标准库中的Vec就是一个泛型集合类型,允许我们存储任意类型的元素。
fn main() {let mut numbers: Vec<i32> = Vec::new();numbers.push(1);numbers.push(2);numbers.push(3);for number in numbers {println!("{}", number);}
}
静态泛型(const 泛型)
Rust1.51版本引入了const泛型,使得你可以在编译时为泛型类型提供常量值。这通常用于数组大小、结构体字段或其他与常量相关的场景。通过const泛型,类型不仅限于具体的类型,也可以是编译时常量。
//在ArrayWrapper结构体中N代表数组的大小 而T则代表元素的类型。
struct ArrayWrapper<T, const N: usize> {data: [T; N],
}impl<T, const N: usize> ArrayWrapper<T, N> {fn new(data: [T; N]) -> Self {ArrayWrapper { data }}fn print(&self) {for item in &self.data {println!("{:?}", item);}}
}fn main() {let arr = ArrayWrapper::<i32, 5>::new([1, 2, 3, 4, 5]);arr.print();
}//泛型T必须支持Debug特性
//N这个泛型参数,它是一个基于值的泛型参数 任何长度的数组都可以传入
fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) {println!("{:?}", arr);
}
fn main() {let arr: [i32; 3] = [1, 2, 3];display_array(arr);let arr: [i32; 2] = [1, 2];display_array(arr);
}
这种方式使得Rust在编译时就能够推断出类型和常量大小,从而实现编译时的类型安全和高效性。
类型别名
Rust允许使用type关键字来创建类型别名,特别是当泛型类型变得过于复杂或冗长时。
type StringResult = Result<String, std::io::Error>;fn get_file_content() -> StringResult {// 假设这是一个读取文件的函数,返回的是一个包含内容或错误的结果Ok("Hello, file!".to_string())
}fn main() {match get_file_content() {Ok(content) => println!("{}", content),Err(e) => println!("Error: {}", e),}
}
默认类型参数
Rust中的泛型不仅可以是任意类型,也可以为泛型参数提供默认值。使用默认值可以减少函数或结构体定义中的样板代码,并使得用户在调用时不必每次都显式提供类型。
struct Wrapper<T = i32> {value: T,
}impl<T> Wrapper<T> {fn new(value: T) -> Self {Wrapper { value }}
}fn main() {let default_wrapper = Wrapper::new(42); //T默认为 i32let string_wrapper = Wrapper::new(String::from("Hello")); //使用 String 类型println!("{}", default_wrapper.value);println!("{}", string_wrapper.value);
}
Sized Trait与泛型
Rust中的类型有一个特殊的trait叫 Sized,它表示一个类型的大小在编译时是已知的。绝大多数类型都实现了Sized trait,但也有一些例外(例如动态大小类型DST,如 str、[T]等)。在泛型中Sized trait很常见,通常它会隐式地应用于泛型参数。
//T: Sized限制了T必须是一个已知大小的类型
fn print_size<T: Sized>(value: T) {println!("Size of value: {}", std::mem::size_of::<T>());
}fn main() {let x = 42;print_size(x);
}//例如str就是一个DST,如果想要在泛型函数中接受动态大小类型可以通过 ?Sized 来消除 Sized 限制
fn print_size<T: ?Sized>(value: &T) {// 允许接受动态大小类型println!("Size of value: {}", std::mem::size_of_val(value));
}fn main() {let s: &str = "hello";print_size(s);
}
常量函数与泛型
const fn即常量函数。const fn允许我们在编译期对函数进行求值。在编译期就计算出一些值,以提高运行时的性能或满足某些编译期的约束条件提高运行时的性能,还使代码更加简洁和安全。
const fn add(a: usize, b: usize) -> usize {a + b
}
const RESULT: usize = add(5, 10);
fn main() {println!("The result is: {}", RESULT);
}//const fn 与 const 泛型相结合
struct Buffer<const N: usize> {data: [u8; N],
}const fn compute_buffer_size(factor: usize) -> usize {factor * 1024
}fn main() {const SIZE: usize = compute_buffer_size(4);let buffer = Buffer::<SIZE> {data: [0; SIZE],};println!("Buffer size: {} bytes", buffer.data.len());
}
泛型的性能
Rust中的泛型在编译时通过 monomorphization(单态化)机制进行优化。即每当一个泛型函数或结构体被实例化时,Rust会根据具体的类型生成专门的代码,从而避免了运行时的性能开销。因此Rust的泛型在运行时与手写的非泛型代码几乎没有区别,提供了与静态类型语言一样的性能。
相关文章:
详解Rust泛型用法
文章目录 基础语法泛型与结构体泛型约束泛型与生命周期泛型与枚举泛型和Vec静态泛型(const 泛型)类型别名默认类型参数Sized Trait与泛型常量函数与泛型泛型的性能 Rust是一种系统编程语言,它拥有强大的泛型支持,泛型是Rust中用于实现代码复用和类型安全…...

移远通信携手紫光展锐,以“5G+算力”共绘万物智联新蓝图
11月26日,2024紫光展锐全球合作伙伴大会在上海举办。作为紫光展锐重要的合作伙伴,移远通信应邀参会。 在下午的物联网生态论坛上,移远通信产品总监胡勇华作题为“5G与算力双擎驱动 引领智联新未来”的演讲,深度剖析了产业发展的趋…...

Mybatis:Mybatis快速入门
Mybatis的官方文档是真的非常好!非常好! 点一下我呗:Mybatis官方文档 MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可…...
微信小程序用户登录页面制作教程
微信小程序用户登录页面制作教程 前言 在微信小程序的开发过程中,用户登录是一个至关重要的功能。通过用户登录,我们可以为用户提供个性化的体验,保护用户数据,并实现更复杂的业务逻辑。本文将为您详细讲解如何制作一个用户登录页面,包括设计思路、代码示例以及实现细节…...

python+django自动化平台(一键执行sql) 前端vue-element展示
一、开发环境搭建和配置 pip install mysql-connector-pythonpip install PyMySQL二、django模块目录 dbOperations ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-313.pyc │ ├── admin.cpython-313.pyc │ ├── apps.cpython-313.pyc │ …...

JavaScript学习总结
前言 JavaScript的学习花的时间比较长,如何进行正确的学习?今天进行总结与整理。 首先,明确JavaScript是什么?它的结构框架是什么,有哪些操作与组成部分。 其次,通过案例实践,清楚达到什么效果…...
Python 3 教程第22篇(数据结构)
Python3 数据结构 本章节我们主要结合前面所学的知识点来介绍Python数据结构。 列表 Python中列表是可变的,这是它区别于字符串和元组的最重要的特点,一句话概括即:列表可以修改,而字符串和元组不能。 以下是 Python 中列表的方…...

AI时代的软件工程:迎接LLM-DevOps的新纪元
在科技日新月异的今天,GPT的问世无疑为各行各业带来了一场深刻的变革,而软件工程领域更是首当其冲,正式迈入了软件工程3.0的新纪元。2024年,作为软件工程3.0的元年,伴随着软件工程3.0宣言的震撼发布,一个全…...
linux安全管理-系统环境安全
1 历史命令设置 1、检查内容 检查操作系统的历史命令设置。 2、配置要求 建议操作系统的历史命令设置。 3、配置方法 编辑/etc/profile 文件,配置保留历史命令的条数 HISTSIZE 和保留历史命令的记录文件大小 HISTFILESIZE,这两个都设置为 5。 配置方法如…...

MindAgent部署(进行中.....)
第一步:pip install -r requirements.txt 问题:如下:就是我的服务器,无法访问github Preparing metadata (setup.py) ... errorerror: subprocess-exited-with-error python setup.py egg_info did not run successfully.│ exi…...

【JavaEE初阶 — 网络编程】TCP流套接字编程
TCP流套接字编程 1. TCP & UDP 的区别 TCP 的核心特点是面向字节流,读写数据的基本单位是字节 byte 2 API介绍 2.1 ServerSocket 定义 ServerSocket 是创建 TCP 服务端 Socket 的API。 构造方法 方法签名 方法说明 ServerS…...
《气候变化研究进展》
《气候变化研究进展》设有气候系统变化、气候变化影响、气候变化适应、温室气体排放、对策论坛、简讯等栏目,其内容包括:国内外气候变化研究的最新成果与进展,以及与气候变化有关的交叉学科,如地球科学、生态与环境科学、人文与社…...

D2545电动工具调速专用控制电路芯片介绍【青牛科技】
概述: D2545 是一块频率、占空比可调的脉冲控制电路。可通过调节外接的电阻和电容大小来控制输出频率和占空比,达到控制电机转速的作用。 主要特点: ● 电源电压范围宽 ● 占空比可调 ● 静态功耗小 ● 抗干扰能力强 应用: ● …...

Unity 2020、2021、2022、2023、6000下载安装
Unity 2020、2021、2022、2023、6000 下载安装 以Unity 6000.0.24fc1下载安装为例: 打开 https://unity.cn/ 优三缔 官方网站; 点击【产品列表】→点击【查看更多】→选择自己需要的版本→点【开始使用】 点击【从Unity Hub下载】 以Windows为例&am…...

33 基于单片机的智能窗帘控制系统
目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机,采用DHT11温湿度传感器检测温湿度,滑动变阻器连接ADC0832数模转换器转换模拟,光敏传感器,采用GP2D12红外传感器,通过LCD1602显示屏显示…...

【CSS in Depth 2 精译_063】10.2 深入理解 CSS 容器查询中的容器
当前内容所在位置(可进入专栏查看其他译好的章节内容) 【第十章 CSS 容器查询】 ✔️ 10.1 容器查询的一个简单示例 10.1.1 容器尺寸查询的用法 10.2 深入理解容器 ✔️ 10.2.1 容器的类型 ✔️10.2.2 容器的名称 ✔️10.2.3 容器与模块化 CSS ✔️ 10.3…...

记录一次 k8s 节点内存不足的排查过程
背景:前端服务一直报404,查看k8s日志,没发现报错,但是发现pods多次重启。 排查过程: 查看pods日志,发现日志进不去。 kubectrl logs -f -n weave pod-name --tail 100查看pod describe kubectl describ…...

探索天空中的“名字”——用Landsat影像记录你的名字形状!
大家好!今天我发现了一个特别有趣的工具——NASA官网上有一个功能,允许你输入自己的名字,然后它会根据Landsat卫星影像显示出与你名字形状相符的地形图。是不是很酷?🎉 🌍 Landsat影像的神奇之处Landsat是N…...

QT6学习第四天 感受QT的文件编译
QT6学习第四天 感受QT的文件编译 使用纯代码编写程序新建工程 使用其他编辑器纯代码编写程序并在命令行运行使用 .ui 表单文件生成界面使用自定义 C 窗口类使用现成的QT Designer界面类 使用纯代码编写程序 我们知道QT Creator中可以用拖拽的方式在 .ui 文件上布局,…...

透视投影(Perspective projection)与等距圆柱投影(Equirectangular projection)
一、透视投影 1.方法概述 Perspective projection(透视投影)是一种模拟人眼观察三维空间物体时的视觉效果的投影方法。它通过模拟观察者从一个特定视点观察三维场景的方式来创建二维图像。在透视投影中,远处的物体看起来比近处的物体小&…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...