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

详解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是一种系统编程语言&#xff0c;它拥有强大的泛型支持&#xff0c;泛型是Rust中用于实现代码复用和类型安全…...

移远通信携手紫光展锐,以“5G+算力”共绘万物智联新蓝图

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

Mybatis:Mybatis快速入门

Mybatis的官方文档是真的非常好&#xff01;非常好&#xff01; 点一下我呗&#xff1a;Mybatis官方文档 MyBatis 是一款优秀的持久层框架&#xff0c;它支持自定义 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的学习花的时间比较长&#xff0c;如何进行正确的学习&#xff1f;今天进行总结与整理。 首先&#xff0c;明确JavaScript是什么&#xff1f;它的结构框架是什么&#xff0c;有哪些操作与组成部分。 其次&#xff0c;通过案例实践&#xff0c;清楚达到什么效果…...

Python 3 教程第22篇(数据结构)

Python3 数据结构 本章节我们主要结合前面所学的知识点来介绍Python数据结构。 列表 Python中列表是可变的&#xff0c;这是它区别于字符串和元组的最重要的特点&#xff0c;一句话概括即&#xff1a;列表可以修改&#xff0c;而字符串和元组不能。 以下是 Python 中列表的方…...

AI时代的软件工程:迎接LLM-DevOps的新纪元

在科技日新月异的今天&#xff0c;GPT的问世无疑为各行各业带来了一场深刻的变革&#xff0c;而软件工程领域更是首当其冲&#xff0c;正式迈入了软件工程3.0的新纪元。2024年&#xff0c;作为软件工程3.0的元年&#xff0c;伴随着软件工程3.0宣言的震撼发布&#xff0c;一个全…...

linux安全管理-系统环境安全

1 历史命令设置 1、检查内容 检查操作系统的历史命令设置。 2、配置要求 建议操作系统的历史命令设置。 3、配置方法 编辑/etc/profile 文件&#xff0c;配置保留历史命令的条数 HISTSIZE 和保留历史命令的记录文件大小 HISTFILESIZE&#xff0c;这两个都设置为 5。 配置方法如…...

MindAgent部署(进行中.....)

第一步&#xff1a;pip install -r requirements.txt 问题&#xff1a;如下&#xff1a;就是我的服务器&#xff0c;无法访问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 &#xff06; UDP 的区别 TCP 的核心特点是面向字节流&#xff0c;读写数据的基本单位是字节 byte 2 API介绍 2.1 ServerSocket 定义 ServerSocket 是创建 TCP 服务端 Socket 的API。 构造方法 方法签名 方法说明 ServerS…...

《气候变化研究进展》

《气候变化研究进展》设有气候系统变化、气候变化影响、气候变化适应、温室气体排放、对策论坛、简讯等栏目&#xff0c;其内容包括&#xff1a;国内外气候变化研究的最新成果与进展&#xff0c;以及与气候变化有关的交叉学科&#xff0c;如地球科学、生态与环境科学、人文与社…...

D2545电动工具调速专用控制电路芯片介绍【青牛科技】

概述&#xff1a; D2545 是一块频率、占空比可调的脉冲控制电路。可通过调节外接的电阻和电容大小来控制输出频率和占空比&#xff0c;达到控制电机转速的作用。 主要特点&#xff1a; ● 电源电压范围宽 ● 占空比可调 ● 静态功耗小 ● 抗干扰能力强 应用&#xff1a; ● …...

Unity 2020、2021、2022、2023、6000下载安装

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

33 基于单片机的智能窗帘控制系统

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

【CSS in Depth 2 精译_063】10.2 深入理解 CSS 容器查询中的容器

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

记录一次 k8s 节点内存不足的排查过程

背景&#xff1a;前端服务一直报404&#xff0c;查看k8s日志&#xff0c;没发现报错&#xff0c;但是发现pods多次重启。 排查过程&#xff1a; 查看pods日志&#xff0c;发现日志进不去。 kubectrl logs -f -n weave pod-name --tail 100查看pod describe kubectl describ…...

探索天空中的“名字”——用Landsat影像记录你的名字形状!

大家好&#xff01;今天我发现了一个特别有趣的工具——NASA官网上有一个功能&#xff0c;允许你输入自己的名字&#xff0c;然后它会根据Landsat卫星影像显示出与你名字形状相符的地形图。是不是很酷&#xff1f;&#x1f389; &#x1f30d; Landsat影像的神奇之处Landsat是N…...

QT6学习第四天 感受QT的文件编译

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

透视投影(Perspective projection)与等距圆柱投影(Equirectangular projection)

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

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist

现象&#xff1a; android studio报错&#xff1a; [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决&#xff1a; 不要动CMakeLists.…...