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约束信息来确保代码中使用的具体类型提供了正确的行为。