当前位置:嗨网首页>书籍在线阅读

03-泛型

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

4.2 泛型

从高级语言诞生之初,追求更好的抽象是语言设计者一直在努力的目标,因此,产生了许多关于代码复用的想法。其中第一个就是函数,函数允许你在某个具名实体中对一系列指令进行分组,这些指令可以在以后调用多次,并且可以根据需要在每次调用时接收任意参数。它们降低了代码的复杂度,并增强了可读性。不过,函数的能力也就仅限于此了。如果你有一个函数,例如 avg,它用于计算给定整数列表的平均值,之后你有一个需求,需要计算浮点数列表的平均值,那么通常的解决方案是创建一个可以对浮点数列表计算平均值的新函数。如果你想计算双精度数值列表平均值该怎么办?我们可能需要再次编写另一个函数。而一遍又一遍地编写相同的函数只是因为它们的参数不同,这对程序员来说就是在浪费宝贵的时间。为了减少这种重复,语言设计者想提供一种表述代码的方法,以便avg函数能够接收多种类型的数值,从而成为一个通用函数,由此通用编程和泛型就诞生了。具有可以接收多种类型的参数的函数是泛型编程的特征之一,当然还有其他地方会用到泛型。我们将在本节讨论所有这些内容。

泛型编程是一种仅适用于静态类型编程语言的技术。它首次出现在ML语言中,是一种静态类型的函数式语言。像Python这样的动态语言采用的是简单类型(duck typing),其中的API是根据它们可以做什么,而不是它们是什么来处理参数的,因此不依赖于泛型。泛型是语言设计特性的一部分,可以实现代码复用,并遵循不重复自己的原则(Don't Repeat Yourself,DRY)。采用这种技术,你可以使用类型占位符来编写算法、函数、方法及类型,并在这些类型上指定一个类型变量(使用单个字母,通常是T、K或V),告知编译器在任何代码中实例化它们时要填充的实际类型。这些类型被称为泛型或元素。单个字母(例如类型T)被称为泛型参数。当你使用或实例化任何泛型元素时,它们会被替换成诸如u32这样的具体类型。

66.png 注意

替换,即每次将泛型元素与具体类型一起使用时,都会在编译时用类型变量T生成该代码的特定副本,并将其替换为具体类型。这种在编译时生成包含具体类型的专用函数的过程被称为单态化,这是执行与多态函数相反的过程。

让我们看一下Rust标准库中已经存在的某些泛型。来自标准库的Vec类型是泛型,其定义如下所示:

pub struct Vec<T> {
    buf: RawVec<T>,
    len: usize,
}

我们可以看到Vec的类型签名在其名称后面包含一个类型参数T,并由一对尖头括号(< >)标识。它的成员字段buf也是泛型,因此Vec自身也必须是泛型。如果我们的泛型“Vec”中不包含“T”,那么即使我们的buf字段中包含T,也会收到以下错误信息:

error[E0412]: cannot find type 'T' in this scope

T需要成为Vec类型定义的一部分。因此,当我们表示Vec时,通常都会使用Vec来表示,或者在知道具体类型时,使用Vect来表示。接下来,让我们看看如何创建自定义泛型。