Rust泛型详解 - 实践

news/2025/10/3 11:23:35/文章来源:https://www.cnblogs.com/ljbguanli/p/19124413

Rust泛型详解 - 实践

泛型可以看作构建函数和类型定义的模板。标准库中有很多常见类型例如Result<T, E>Option<T>Vec<T>等都是泛型实现的。主要用于代码的特化。Rust是静态类型语言,因此泛型的类型参数(T)需要在编译期解析为具体类型,这种特性就是参数化多态性。泛型的实现还采用单态化技术,会根据实际传入的类型参数,将泛型实例化为唯一的专用类型。
泛型的优点:

  • 代码复用:只需编写一套代码,可以用于不同的类型。
  • 重构:重构变得更简单,因为泛型只有一份源码,不需要维护多份类型不同但功能相同的代码
  • 扩展性:可扩展性强,未来即使出现新的数据类型,泛型代码依然适用。
  • 更不容易犯错:使用泛型减少了大量重复代码的实现,潜在的错误也变少。
  • 独特功能:Rust中的泛型机制带来了独特的能力->函数重载

泛型函数

泛型函数是使用类型参数的函数模板,用于创建具体函数,

  • 类型参数要在函数名后使用<>声明
  • 命名惯例使用大驼峰命名,第一个类型参数一般用T,接着是U、V等
fn function_name<T>(param: T)->T {let variable: T;}

示例

fn swap<T, U>(tuple: (T, U))->(U, T) {(tuple.1, tuple.0)}fn main() {let tuple = (1, "hello");let tuple1 = ("hello".to_string(), "world".to_string());let tuple2 = (3.14, 98);let t_swap = swap(tuple);let t1_swap = swap(tuple1);let t2_swap = swap(tuple2);println!("{:?}", t_swap);println!("{:?}", t1_swap);println!("{:?}", t2_swap);}

编译器自动推导出了具体的类型,编译器会根据函数定义,选择调用对应的函数版本。

编译器通常能从参数类型推导出对应的类型参数,但如果无法推导出具体类型,就需要显式指定类型

function_name::<type,...>(arg,...)

示例

fn do_something<T: Default>()->T {let value: T = T::default();value}fn main() {let ret = do_something::<i8>();println!("{}", ret);}

泛型约束

在编译期,编译器对这些参数类型的实际类型并不了解,因此,编译器需要对使用类型参数的代码添加合理的限制。
可以把类型参数看作一个装着某种工具的黑盒子,你不知道里面具体是什么,但是你想安全地执行一些操作,这个时候会看有关于盒子内容的提示会非常有用。
trait约束就是用来限制类型参数的行为,可以限定单个或多个trait,每个trait都会告诉编译器类型参数应该具备哪些能力。

使用(:)用于添加trait约束,如<T: Trait>

use std::fmt::Display;
fn do_something<T: Display>(t: T) {println!("{}",t);}fn main() {do_something(20);}

因为格式化字符串中的{}占位符需要实现Display trait,编译器不能假设类型参数T具有此特性。

可以给类型参数指定多个限制

<T: Trait1+Trait2+...>

示例

use std::{cmp::Ordering, fmt::Display};
fn largest<T: Ord+Display>(arg1: T, arg2: T) {match arg1.cmp(&arg2) {Ordering::Less => println!("{arg1} < {arg2}"),Ordering::Greater => println!("{arg1} > {arg2}"),Ordering::Equal => println!("{arg1} == {arg2}"),}}fn test() {largest(1, 2);largest("arg1", "arg2");largest('a', 'b');largest(100, 99);}fn main() {test();}

largest是一个泛型函数,用于比较并输出结果。
要支持比较,这个类型必须实现Ord trait; 使用占位符{},要求这个类型必须实现Display,这两个trait都被应用与T的约束。

where

where是约束的另一种表示方法,这种方法的表达力更强

use std::fmt::Debug;
fn do_something<T>(t: T)where T: Debug {println!("{:?}", t);}fn main() {let tuple = (1,2,3,5);do_something(tuple);}

泛型结构体

除了函数之外,结构体同样支持泛型,在定义结构体时,可以在结构体名称后面加上<T> 之后该参数可以被用于结构体定义的任何位置(字段和方法)

struct Wrapper<T> {internal: T}fn main() {let obj = Wrapper {internal: 24};/* 会被单态化成i32类型struct wrapper {internal: i32}*/}

由于单态化机制,编译器会用i32类型实例化Wrapper结构体

泛型结构体不仅可以使用类型参数定义字段,还可以将类型参数用于方法定义。

use std::fmt::Debug;#[derive(Debug)]
struct Wrapper<T> {internal: T}impl<T: Copy> Wrapper<T> {fn get(&self) -> T {self.internal}}fn main() {let obj = Wrapper { internal: 20 };let obj1 = Wrapper {internal: "hello".to_string() };let ret = obj.get();println!("{}",ret);}

只有字段类型实现了Copy的T,才能调用该impl块内的所有方法。由于set方法需要创建T类型的拷贝,所以需要T实现Copy trait。而String类型不属于实现了Copy trait的类型,因此实例化后不具备get方法。

除了从结构体那里继承的类型参数,方法也可以定义专属于自己的类型参数。

use std::fmt::{Debug, Display};#[derive(Debug)]
struct Wrapper<T> {internal: T}impl<T: Copy+Display> Wrapper<T> {fn display<U: Display>(&self, prefix: U, suffix: U) {println!("{prefix} {} {suffix}", self.internal);}}fn main() {let obj = Wrapper { internal: 20 };obj.display("(",")");}

关联函数

你可以将泛型与关联函数一起使用

use std::fmt::{Debug, Display};#[derive(Debug)]
struct Wrapper<T> {internal: T}impl<T: Display> Wrapper<T> {fn hello(name: T) {println!("hello {}",name)}}fn main() {Wrapper::hello("张三");}

由于hello方法传入了一个&str类型的参数,编译器可以推断出T的类型,因此就不需要手动指定。
而下面这种情况需要手动指定类型:

use std::fmt::{Debug, Display};#[derive(Debug)]
struct Wrapper<T> {internal: T}impl<T> Wrapper<T> {fn hello() {println!("helloworld");}}fn main() {Wrapper::<&str>::hello();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/925820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设课程的感想在线考试系统网站开发

算法提高课整理 CSDN个人主页&#xff1a;更好的阅读体验 原题链接 题目描述 给定一个长度为 n n n 的数组&#xff0c;数组中的第 i i i 个数字表示一个给定股票在第 i i i 天的价格。 设计一个算法来计算你所能获取的最大利润&#xff0c;你最多可以完成 k k k 笔交易…

怎么做自己的购物网站怎么给自己建网站

文章目录树状数组lowbit线段树与树状数组单点修改区间查询区间修改区间求和二维树状数组离线树状数组例题POJ&#xff1a;starsMooFest[SDOI2009]HH的项链Turing TreeCounting SequencesZip-line树状数组 用于快速高效的计算与前缀和相关的信息 lowbit int lowbit( int i ) …

有个做搞笑视频的网站桂林市天气预报15天准确

在开发项目过程中&#xff0c;为了方便调试代码&#xff0c;经常会向stdout中输出一些日志&#xff0c;默认的这些日志就直接显示在了终端中。而一般的应用服务器&#xff0c;第三方库&#xff0c;甚至服务器的一些通告也会在终端中显示&#xff0c;这样就搅乱了我们想要的信息…

番禺 大石网站建设建筑模板制作过程

是什么 官网&#xff1a;Redis cluster specification | Redis 由于数据量过大&#xff0c;单个Master复制集难以承担&#xff0c;因此需要对多个复制集进行集群&#xff0c;形成水平扩展每个复制集只负责存储整个数据集的一部分&#xff0c;这就是Redis的集群&#xff0c;其作…

AT_abc205_e [ABC205E] White and Black Balls

本质上就是将卡特兰数的 \(y = x\) 这条限制线移到了 \(y = x + k\) 这条限制线,格路计数即可。

transformers音频实战01-音频概念 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

做发包业务网站wordpress主题谁的最好

说明 本文根据B站up主唐老狮的课程所学所记 目录 说明本文根据B站up主唐老狮的课程所学所记 UML面向对象七大原则总体实现目标单一职责原则&#xff08;SRP&#xff0c;Single Responsibility Principle&#xff09;开闭原则&#xff08;OCP&#xff0c;Open-Closed Principle…

网站建设介绍大全杭州网络推广专员

浅谈web应用的负载均衡、集群、高可用(HA)解决方案转载于:https://www.cnblogs.com/hfultrastrong/p/7887420.html

Python 自动化导出PDF表格:List、Dictionary、Pandas DataFrame和数据库实例演示 - 指南

Python 自动化导出PDF表格:List、Dictionary、Pandas DataFrame和数据库实例演示 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !importan…

Rust Slint库达成桌面萌宠源码分享(包含拖动、右键菜单效果)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Redis 持久化机制 - 教程

Redis 持久化机制 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

行业seo网站优化方案厦门优化公司

文章目录 背景介绍 问题描述 分析排查 解决方案 总结归纳 背景介绍 在一个嵌入式软件项目中&#xff0c;有一段使用C语言写的嵌入式代码&#xff0c;功能是把CAN总线上的几帧报文接收进来&#xff0c;并解析出数据。示例如下&#xff1a; 乍一看感觉挺简单&#xff0c;想着…

网站建站图片汉滨区住房和城乡建设局网站

在进行绘图时必须考虑这两种坐标。 世界坐标是整个区域的坐标&#xff0c;而页面坐标是可视区的坐标。这两种坐标是通过滚动条来体现出来的。 页面坐标的原点始终是窗口可视区的坐上角&#xff0c;世界坐标的原点始终不变&#xff0c;这两种坐标和VC中的屏幕坐标和客户坐标很…

2025染井吉野樱公司 TOP 种植服务推荐排行榜,染井吉野樱花苗,五公分染井吉野樱,十公分染井吉野樱,染井吉野樱批发,染井吉野樱基地,染井吉野樱花树公司推荐

引言在樱花苗木采购与景观工程实施过程中,分枝点规格的把控已成为行业突出痛点。当前市场上,染井吉野樱苗木分枝点标准混乱,从 0.5 米到 3 米不等的规格随意标注,缺乏统一规范,导致采购方难以精准匹配绿化需求。部…

网站建设如何定价广州网站制作怎样

Facebook广告是海外营销的一大利器&#xff0c;但是随着互联网的发展&#xff0c;有部分不法分子正在利用他进行盈利&#xff0c;导致Facebook官方安全审核日益严格&#xff0c;不少卖家遭遇封号问题&#xff01;这篇文章就来教你如何更好地管理 Facebook广告帐户&#xff0c;实…

如何建立自己的摄影网站做电商网站用什么框架

来源&#xff1a;AI前线 作者&#xff1a;Jiang Chen&#xff0c;Moveworks 机器学习副总裁译者&#xff1a;王强策划&#xff1a;刘燕从 Siri 到 Alexa 再到谷歌助手&#xff0c;今天我们已经被各种人工智能系统包围了。它们的设计目标只有一个&#xff1a;理解我们。我们已经…

鄂州网站建设与设计乐器网站模板

windows2003-建立域 Active Directory建立DNS建立域查看日志xp 加入域 Active Directory 活动目录是一个包括文件、打印机、应用程序、服务器、域、用户账户等对象的数据库。 常见概念&#xff1a;对象、属性、容器 域组件&#xff08;Domain Component&#xff0c;DC&#x…

glazewm_windows平铺窗口管理器使用方法

1.在github上寻找预构建版本 2.双击安装 3.关闭与zebra有关的命令 配置文件在 C:\Users{yourname}.glzr\glazewm\config.yaml 打开这个文件 默认这条指令是没有注释的,我这边直接注释掉这样软件启动就不会报错了4.添加…

详细介绍:LeetCode热题100(1-7)

详细介绍:LeetCode热题100(1-7)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&…

树莓派搭建NAS之三:使用OpenList挂载网盘

移动硬盘中发现有之前备份的文件,并且监控是一直在写盘,容易将磁盘写坏,之前备份的数据就无法读出。找了半天找到了个不用的32GB的U盘,可以先用着。 U盘的空间太小,连续录制1-2天的时间就会满了,之前的监控也无法…