问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

Rust泛型和Trait

发布网友 发布时间:2024-10-05 22:43

我来回答

1个回答

热心网友 时间:2024-11-16 02:45

Hi,今天来学习一下Rust当中的泛型和Trait。我们都知道泛型是具体类型或其他属性的抽象替代。在编写代码时,我们可以直接描述泛型的行为,或者它与其他泛型产生的联系,而无须知晓它在编译和运行代码时采用的具体类型。而trait被用来向Rust编译器描述某些特定类型拥有的且能够被其他类型共享的功能,它使我们可以以一种抽象的方式来定义共享行为。我们还可以使用trait约束来将泛型参数指定为实现了某些特定行为的类型。闲话少说开始今天的学习内容。

学过C++的都知道C++里面有template的概念,例如下面代码所示:

其实Rust里的泛型也跟这个是有点相似的。下面就来看看Rust中的泛型。

使用泛型来定义一个函数时,我们只需将泛型放置在函数签名中通常用于指定参数和返回值类型的地方。例如下面所示:

具体使用例子,代码如下所示:

运行结果如下所示:

2. 泛型结构

同样地,我们也可以使用><泛型语法来定义在一个或多个字段中使用泛型的结构体。它的定义格式如下所示:

泛型结构定义例子如下所示:

我们需要注意的一点就是,上面例子中Person结构体里的age和sex使用了泛型,我们在实例化结构体时这两个字段的类型必须是相同的,否则代码会编译不同过。就如下面所示:

错误输出如下所示:

解决办法就是定义多个泛型类型,做法如下所示:

3. 泛型枚举

泛型枚举我们之前在Rust错误处理的文章里就接触过了,例如标准库里面的Option枚举和Result枚举,这里我就不举例了。

4. 泛型方法

在之前的文章中我们讲过结构体或枚举并为其实现过方法,而方法也可以在自己的定义中使用泛型。具体如下所示:

泛型方法和泛型函数从定义形式上是一样的,只不过方法要与一种类型绑定在一起。

使用Trait定义共享行为

trait中文直译为特征它被用来向Rust编译器描述某些特定类型拥有的且能够被其他类型共享的功能,它使我们可以以一种抽象的方式来定义共享行为。我们还可以使用trait约束来将泛型参数指定为实现了某些特定行为的类型。

trait与其他语言中常被称为接口的功能类似,但也不尽相同。类型的行为由该类型本身可供调用的方法组成。当我们可以在不同的类型上调用相同的方法时,我们就称这些类型共享了相同的行为。具体看例子如下所示:

乍一看还真的跟go语言定义接口一样呢。一个trait可以包含多个方法:每个方法签名占据单独一行并以分号结尾。

2. 实现trait

单独定义trait是没啥用的,我们得去实现它才能发挥它的作用,具体操作如下所示:

Note: 实现trait的一个*,只有当trait或类型定义于我们的库中时,我们才能为该类型实现对应的trait。我们不能为外部类型实现外部trait。例如,我们不能在自己当前的库内为Vec实现Display trait,因为Display与Vec都被定义在标准库中,而没有定义在我们库中。这个*被称为孤儿规则之所以这么命名是因为它的父类型没有定义在当前库中。

3. trait的默认实现

我们可以在trait中的提供默认行为,这样可以使我们无须为每一个类型的实现都提供自定义行为。当我们在为某个特定类型实现trait时,可以选择保留或重载每个方法的默认行为。具体做法如下所示:

4. 将trait作为参数

trait也属于Rust类型系统中的一种类型,所以我们也可以将其作为参数传递给函数或方法。

这里我们将Dosomething这个trait作为参数传递给了trait_fn函数,并在该函数体内调用了doing函数,注意我们没有指定具体的类型。在main函数中我们调用了trait_fn函数并将Worker结构体实例作为参数传递进去了,之所以可以将Woker的实例作为参数传递给trait_fn函数是因为我们实现了Dosomething这个trait,如果换作其他类型的参数是不可以滴,即只要实现了该trait的某种类型,我们就可以调用其提供的行为。这么一看还跟接口有点相像。

5. trait约束

我们可以为trait指定约束,具体形式有很多种,具体如下所示:

上面的(item: T)的意思是函数只能接收实现了Dosomething这个trait的类型,也就是说*了T的类型。

我们还可以使用+语法来指定多个trait约束,具体如下所示:

除此之外,我们还可以使用where从句来限定trait约束,例如下面所示:

6. 返回实现了trait的类型

我们可以在方法里返回值中使用impl Trait语法,用于返回某种实现了 trait的类型,具体操作如下所示:

在上面的代码中我们通过在返回类型中使用impl Dosomething,我们指定return_trait_type函数返回一个实现了Dosomething trait的类型作为结果,而无须显式地声明具体的类型名称。

7. 使用trait约束来有条件地实现方法

我们可以通过在带有泛型参数的impl代码块中使用trait约束,这样我们就可以单独为实现了指定trait的类型编写方法了,具体作法如下所示:

上面代码例子中对结构体Point作了trait约束,意思是只有在内部类型T实现了PartialOrd与Display这两个trait的前提下,才会实现cmp_xy_value方法。

小结

今天我们学习了Rust中泛型和trait的基础内容,并且我们在借助于trait和trait约束,使用泛型参数来消除重复代码的同时,向编译器指明自己希望泛型拥有的功能。而编译器则可以利用这些trait约束信息来确保代码中使用的具体类型提供了正确的行为。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
抖音弹幕怎么关掉?怎么关闭抖音弹幕? 惠普LaserJet P3005D是否支持B5纸的双面打印? word打印出图片总是缺一部分怎么办-word打印图片不完整怎么解决_百度... 理想one哪里产的车辆? 抚州抚州ONE在哪里? one地址在哪里? 如何在图片上写字(如何在图片上添加文字) 网商贷为什么钱没到账 高级经济师职称怎么评 高级经济师需要评审吗 电瓶车上高速公路会罚款多少 反导系统以色列 2016款本田歌诗图怎样打开导航 杨继洲的《针灸大全》编撰背景及内容详解 纪梵希海洋香榭喷法技巧 针灸大成的作者 针灸大成《针灸大成》-著作简介 针灸大成《针灸大成》-与山西的渊源 哈出行车主怎么切换导航 2023年不顺的星座有哪些 危机较多陷入僵局则比较糟糕 ...日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 1 1月10日到2月6日有多少天 高速公路中间隔离带绿色的一片一片的是干什么用的,为什么绿色一片... 小学一年级创作以春节为主题的绘本 猫猫的后肢瘦的只剩骨头了,怎么回事。之前都好好的,这几天突然瘦的... 稻壳会员登录口在哪稻壳会员登录 夫妻之情象兄弟之情这是什么感情 数字无绳电话与无绳电话有什么区别?? ...的时候每次咽下去都感觉胸口有什么东西堵着,喝水也有,不过喝水比较... 胸口痛,吃饭、喝水甚至咽口水都会感觉胸口痛 Rust语言基础(八)struct、enum和Option ...又可能没绑手机号或忘了绑的手机号码怎样才能找回账号呢 Rust Enum Layout 的优化 dest汽车按键 Rust语言中的Result:不得不处理的返回值 拜读Rust权威指南-使用Result类型来处理可能失败的情况(四) 【译】Rust中的Vec类型 rust中,some到底是什么类型?因为枚举内可以包含多种类型, 两百行Rust代码解析绿色线程原理(四)一个绿色线程的实现 Rust中定义一个变量占用多少内存? 非此即彼属于什么关系 不是就是这个关联词有什么作用 吃生的花生米好处和坏处 吃生的花生米对人有什么好处和坏处 每天生吃多少花生米对身体有好处? 英菲尼迪导航怎么操作? 麾托罗拉xt1079有没有微信截图功能 新飞冰箱温度1冷还是7冷 冰箱档位1凉还是7凉,新飞冰箱1-7档哪个最冷_冰箱1度冷还是7度冷_新飞... 品牌授权合同 耳朵里有回声好还是无回声好