学习Rust的第16天:泛型类型

泛型类型是减少代码重复的好方法,因此它们对性能有巨大的影响,通过利用Rust中的泛型类型,开发人员可以编写更通用和可重用的代码,同时保持类型安全和性能。这种方法不仅减少了冗余,还增强了代码的可维护性和可扩展性,还可以促进更清晰、更灵活的设计,使开发人员能够轻松地适应不断变化的需求。

Introduction 介绍

Generic types in Rust allow you to write functions, structs, and enums that can operate on multiple data types without sacrificing type safety, enabling code reuse and flexibility. Let’s take a look at a use case.
Rust中的泛型类型允许您编写可以对多种数据类型进行操作的函数,结构和枚举,而不会牺牲类型安全性,从而实现代码重用和灵活性。让我们来看看一个用例。

fn find_max(x: i32, y: i32) -> i32{if x > y {x}else{y}
}fn main(){let result: i32 = find_max(9,10);println!("The maximum value is : {}", result);
}

Output: 输出量:

The maximum value is 10

If I wanted to use the same function for characters or floating point numbers, I would have to create a new function with the specific types with basically the same logic. Generic type helps to reduce this code duplication.
如果我想对字符或浮点数使用相同的函数,我必须创建一个具有基本相同逻辑的特定类型的新函数。泛型类型有助于减少这种代码重复。

We can declare multiple generic types for a function/struct. Single generic types are generally denoted by T which stands for Type.
我们可以为一个函数/结构声明多个泛型类型。单个泛型类型通常用 T 表示,它代表 Type 。

Generic types are declare within <> in a function.
泛型类型在函数中的 <> 中声明。

Example : 范例:

fn find_max<T: PartialOrd>(x: T, y: T) -> T {if x > y {x} else {y}
}fn main() {let result = find_max(10, 5);println!("The maximum value is: {}", result);let result_float = find_max(4.5, 3.2);println!("The maximum value is: {}", result_float);let result_char = find_max('x','a');println!("The maximum value is: {}", result_char);
}

Output: 输出量:

The maximum value is: 10
The maximum value is: 4.5
The maximum value is: x

Explanation : 说明:

  • - The find_max function is defined with the generic type argument T.
    find_max 函数是用泛型类型参数 T 定义的。
  • The <T: PartialOrd> syntax indicates that T must implement the PartialOrd trait, which allows for comparisons across values of type T.
    <T: PartialOrd> 语法表明 T 必须实现 PartialOrd trait,这允许在类型 T 的值之间进行比较。
  • PartialOrd is a trait in Rust that defines partial ordering relations (less than, less than or equal to, greater than, greater than or equal to) between values of the same type.
    PartialOrd 是Rust中的一个trait,它定义了相同类型的值之间的偏序关系(小于,小于或等于,大于,大于或等于)。
  • Types implementing PartialOrd can be compared with the comparison operators (<<=>>=) and can be used in functions that rely on ordering, like sorting algorithms or in this case, finding the maximum value.
    实现 PartialOrd 的类型可以与比较运算符( < , <= , > , >= )进行比较,并且可以用于依赖于排序的函数中,例如排序算法或在本例中查找最大值。
  • This allows the function to work with a variety of types as long as they support comparison using the PartialOrd trait.
    这允许函数处理各种类型,只要它们支持使用 PartialOrd trait进行比较。
  • By utilizing generics, the function gets flexibility and reusability while maintaining type safety.
    通过使用泛型,函数在保持类型安全的同时获得了灵活性和可重用性。
  • The function returns a value of type T, guaranteeing that the maximum value is the same as the input values.
    该函数返回一个类型为 T 的值,保证最大值与输入值相同。

Generic types in Structs 结构中的泛型类型

Let’s say I want to store a co-ordinates of a point. Here’s a struct that I would normally use
假设我想存储点的坐标。这里有一个我通常会使用的结构

struct Point{x: i32,y: i32,
}fn main(){let point = Point{x: 3, y: 10};//This line will not work because out struct can only store signed 32 bit integerslet point2 = Point{x:3.4, y: 6.9};
}

Let’s fix this issue: 让我们解决这个问题:

struct Point<T>{x: T,y: T,
}fn main(){let point = Point{x: 3, y: 10};let point2 = Point{x:3.4, y: 6.9};//This line will not work because out struct can not store two different data typeslet point3 = Point{x:3.4, y: 6};
}

To fix this, we can add another generic type in out struct.
为了解决这个问题,我们可以在out结构中添加另一个泛型类型。

struct Point<T, U>{x: T,y: U,
}fn main(){let point = Point{x: 3, y: 10};let point2 = Point{x:3.4, y: 6.9};let point3 = Point{x:3.4, y: 6};
}

Now all of this works, and that’s how we can use Generic types in structs…
现在所有这些都可以工作了,这就是我们如何在结构中使用泛型类型。

Generic types in enums 枚举中的泛型类型

We can do the same with enums, I’ll show you an example of two most popular enums with generic types:
我们可以对枚举做同样的事情,我将向你展示两个最流行的泛型枚举的例子:

enum Option<T>{Some(T),None,
}
enum Result<T,E>{Ok(T),Err(E),
}

Generic types in methods 方法中的泛型类型

If you recall, We can use impl to declare implementation blocks for a struct to declare methods for a struct.
如果你还记得的话,我们可以使用 impl 来声明结构的实现块来声明结构的方法。

Getting back to our Point struct, Let’s declare an implementation block using generic types for the struct.
回到我们的Point结构,让我们使用结构的泛型类型声明一个实现块。

​
enum Result<T,E>{Ok(T),Err(E),
}​

The method X retrurns the X co-ordinate of the point taking the reference of self
方法X返回以 self 为参考的点的X坐标

Notice how while declaring the struct is used T as the generic type and in the impl block I am using U this shows that both of these generic types are not tied together.
请注意,当声明结构体时,我使用 T 作为泛型类型,而在 impl 块中,我使用 U ,这表明这两个泛型类型没有绑定在一起。

Now what will happpen if I declare another impl block with a concrete type?
现在,如果我用一个具体类型声明另一个 impl 块,会发生什么?

struct Point<T>{x: T,y: T,
}impl<U> Point<U>{fn x(&self) -> &U {&self.x}
}impl Point<i32>{fn y(&self) -> i32{self.y}
}fn main(){let point1 = Point{x: 3, y: 10};let point2 = Point{x:3.4, y: 6.9};println!("X: {}, Y: {}",point1.x(),point1.y());println!("X: {}, Y: {}",point2.x(),point2.y);
}

The method y is only available to the instances which have the x and y values as signed 32 bit integers, whereas the x method can be used on the instances of any type.
方法 y 仅适用于具有作为有符号32位整数的 x 和 y 值的实例,而方法 x 可用于任何类型的实例。

Mixing up generics 混淆泛型

Let’s take a look at a more complex example where we had two generics in out Point struct and understand the need of mixing them up…
让我们来看看一个更复杂的例子,我们在out Point结构中有两个泛型,并理解混合它们的必要性。

struct Point<T, U>{x: T,y: U,
}impl<T,U> Point<T,U>{fn mixup<V, W>(self,other: Point<V, W>) -> Point<V, W>{Point{x: self.x,y: other.y,}}
}fn main(){let point = Point{x: 3, y: 10};let point2 = Point{x:3.4, y: 6.9};let point3 = Point{x:3.4, y: 6};let point4 = point1.mixup(point2);println!("X: {}, Y: {}",point4.x, point4.y);
}
  • The code defines a generic struct called Point<T, U>, which represents a point in a 2D space. It has two fields x and y, each with its own generic type T and U respectively.
    代码定义了一个名为 Point<T, U> 的通用结构,它表示2D空间中的一个点。它有两个字段 x 和 y ,每个字段分别有自己的泛型类型 T 和 U 。
  • An implementation block (impl) for the Point<T, U> struct is provided. Inside this block, there's a method mixup<V, W>(self, other: Point<V, W>) -> Point<V, W>. This method takes another Point instance as an argument with potentially different types (V and W) for its x and y values.
    提供了 Point<T, U> 结构的实现块( impl )。在这个块中,有一个方法 mixup<V, W>(self, other: Point<V, W>) -> Point<V, W> 。此方法将另一个 Point 实例作为参数,其 x 和 y 值可能具有不同的类型( V 和 W )。
  • Inside the mixup method, a new Point instance is created with the x value from the current Point instance (self.x) and the y value from the other Point instance (other.y). Both x and y values are of the generic types V and W respectively.
    在 mixup 方法内部,使用来自当前 Point 实例( self.x )的 x 值和来自 other Point 实例( other.y )的 y 值创建新的 Point 实例。 x 和 y 值分别是泛型类型 V 和 W 。
  • In the main function: 在 main 函数中:
  • Four Point instances are created: pointpoint2point3, and point4.
    创建了四个 Point 实例: point 、 point2 、 point3 和 point4 。
  • point4 is created by calling the mixup method on point1 (of type Point<i32, i32>) with point2 (of type Point<f64, f64>). This demonstrates mixing up two different generic types.
    point4 是通过使用 point2 (类型 Point<f64, f64> )调用 point1 (类型 Point<i32, i32> )上的 mixup 方法创建的。这演示了两种不同泛型类型的混合。
  • Finally, the x and y values of point4 are printed to the console.
    最后,将 point4 的 x 和 y 值打印到控制台。

Why mix up generics? 为什么要混淆泛型?

V and W are like placeholders for types. We use them in the mixup method because it lets us mix and match different types for the x and y values of two Point instances. This flexibility makes our code more versatile because it allows us to work with different types without having to change the struct itself. So, V and W are used instead of T and U to keep things clear and flexible in the method.
V 和 W 就像类型的占位符。我们在 mixup 方法中使用它们,因为它允许我们混合和匹配两个 Point 实例的 x 和 y 值的不同类型。这种灵活性使我们的代码更通用,因为它允许我们使用不同的类型,而不必改变结构本身。因此,使用 V 和 W 而不是 T 和 U 来保持方法的清晰和灵活性。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

AI大模型探索之路-实战篇2:基于CVP架构-企业级知识库实战落地

目录 前言 一、概述 二、本地知识库需求分析 1. 知识库场景分析 2. 知识库应用特点 3. 知识库核心功能 三、本地知识库架构设计 1. RAG架构分析 2. 大模型方案选型 3. 应用技术架构选型 4. 向量数据库选型 5. 模型选型 三、本地知识库RAG评估 四、本地知识库代码落地 1. 文件…

服务器基础知识(1)

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;服务器❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 1、什么是服务器 服务器是计算机的一种&#xff0c;它比普通计算机运行更快、负载更高、价格更贵。服务…

WIFI/BT中蓝牙的硬件资源是如何调度的 UART和PCM接口传输的是什么信号

安卓或IOS手机中&#xff0c;wifi/bt中的蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。M.2 wifi/bt模块或其他形式的模块中&#xff0c;蓝牙是如何调度硬件资源的&#xff0c;尤其是UART和PCM是如何分配的。今天我们就图文并茂的解决这个问题。 蓝牙文件…

MATLAB使用速成 第三章(MATLAB绘图)

一、二维平面作图 1、简单的x-y坐标图 x、y是长度相同的向量&#xff0c;以x的分量为横坐标&#xff0c;y的分量为纵坐标&#xff0c;作平面曲线&#xff0c;使用命令plot(x,y)。&#xff08;可以省略参数x&#xff0c;这样将会以y的分量下标为横坐标&#xff0c;y的分量为纵坐…

如何在极狐GitLab 中用 docker in docker 的方式使用 docker?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab &#xff1a;https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署…

C语言游戏实现——贪吃蛇

思路讲解 ** 贪吃蛇游戏是要求我们要操控一条蛇&#xff0c;在游戏规定的空间之内&#xff0c;进行吃食物&#xff0c;吃到一个就增加蛇身的长度&#xff0c;并且游戏得分加1&#xff0c;如果吃到自己&#xff0c;和碰到墙就算死亡&#xff0c;同时可以增加蛇的速度和减慢蛇的…

Python开源项目周排行 2024年第8周

#2024年第8周2024年4月12日1llama3当知无愧AI LLM领域当红炸子鸡&#xff01;Llama 3 是由 Meta AI 开发的大型语言模型 (LLM)&#xff0c;于 2024 年 4 月发布。它基于 Megatron-Turing NLG 模型架构&#xff0c;并在超过 15 万亿个标记的公开可用数据上进行了预训练&#xff…

算法训练营day15

一、层序遍历 参考链接7.2 二叉树遍历 - Hello 算法 (hello-algo.com) 层序遍历本质上属于广度优先遍历&#xff0c;也称广度优先搜索&#xff0c; BFS通常借助队列的先入先出的特性实现 参考链接102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; 像这种较为…

百度GL地图实现选点获取经纬度并且地址逆解析

index.html引入 <script src"https://api.map.baidu.com/api?typewebgl&v1.0&ak你的ak"></script>组件使用 <el-input:disabled"[详情].includes(title)"v-model"formData.site"placeholder""><templat…

【行为型模型】迭代器模式

一、迭代器模式概述 迭代器模式定义&#xff1a;提供一种方法顺序访问一个聚合对象中的各个元素&#xff0c;而又不暴露其内部的表示。把游走的任务放在送代器上&#xff0c;而不是聚合上。这样简化了聚含的接口和实现,也让责任各得其所。(对象行为型) 迭代器模式的优缺点&…

virtualbox 网络设置实现主机和虚拟机互相访问

前言 一般来说&#xff0c;virtualbox 虚拟机的上网模式是 NAT。这样虚拟机可以上网并访问宿主机&#xff0c;但宿主机无法访问虚拟机&#xff0c;也无法 ping 通。下面介绍双网卡模式&#xff0c;实现虚拟机和宿主机能够互相访问 ping 通。 双网卡模式 进入虚拟机的网络设置…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之一 简单人脸识别 一、简单介绍 二、简单人脸识别实现原理 三、简单人脸识别案例实现简单步…

C语言—深度剖析函数指针,函数指针数组

我们先来看一段代码 #include <stdio.h> void test() {printf("hehe\n"); } int main() {printf("%p\n", test);printf("%p\n", &test);return 0; }输出的是两个地址&#xff0c;这两个地址是 test 函数的地址。 那我们的函数的地址…

杰理695的UI模式LED灯控制

UI模式LED灯修改每个模式对应的LED灯闪烁修改在ui_normal_status_deal(u8 *status, u8 *power_status, u8 ui_mg_para)

关系型数据库中primary key和foreign key、索引的作用

文章目录 一、关系型数据库中主键(primary key)和外键(foreign key)的概念。二、MySQL索引的作用(索引的优缺点)一、关系型数据库中主键(primary key)和外键(foreign key)的概念。 二、MySQL索引的作用(索引的优缺点) MySQL索引是一种数据结构,它可以提高查询性能…

MATLAB初学者入门(13)—— 遗传算法

遗传算法是一种受自然选择和遗传学启发的搜索启发式算法&#xff0c;用于解决优化和搜索问题。它模拟了自然界中生物的进化过程&#xff0c;包括基因的选择、交叉&#xff08;杂交&#xff09;和变异。 MATLAB 提供了一个方便的工具箱&#xff0c;即全局优化工具箱&#xff0c;…

网卡技术解密:理解网卡背后的原理

✍✍在这个信息爆炸的时代&#xff0c;网卡承载着无数数据的流动&#xff0c;是我们日常生活和工作不可或缺的一部分。但是&#xff0c;您是否曾经好奇过&#xff0c;这些小小的硬件是如何在瞬息万变的网络世界中稳定地发挥作用的呢&#xff1f; 想象一下&#xff0c;每当我们…

计算机缺少msvcp120.dll如何解决,7种详细的修复方法分享

msvcr120.dll文件是微软Visual C运行时库的一部分&#xff0c;版本号为12.0。这个DLL文件包含了许多用于支持在Windows上运行的应用程序的重要函数和组件。它是确保某些程序能够正确执行的关键组成部分&#xff0c;特别是那些使用C编写或依赖于某些Microsoft库的程序。 当用户…

家用充电桩有必要买21KW交流充电桩吗?

随着电动汽车的普及和人们环保出行意识的增强&#xff0c;充电设施的需求日益增长。在选择充电桩时&#xff0c;很多人会考虑到充电速度、功率等因素。而作为交流充电桩中充电效率最高的一种&#xff0c;21KW交流充电桩是否值得购买呢&#xff1f; 从成本角度来看&#xff0c;2…

只需几步,即可享有笔记小程序

本示例是一个简单的外卖查看店铺点菜的外卖微信小程序&#xff0c;小程序后端服务使用了MemFire Cloud&#xff0c;其中使用到的MemFire Cloud功能包括&#xff1a; 其中使用到的MemFire Cloud功能包括&#xff1a; 云数据库&#xff1a;存储外卖微信小程序所有数据表的信息。…