
4.2 泛型
本章的最后一节,我们来谈谈泛型。在声明一个变量时,通常会用到var,即没有定义是何种类型,因为在Dart编程语言中,类型是可选的。那么,既然类型是可选的,为什么还要用泛型、泛型如何使用,以及它的典型应用场景是什么呢?通过本节的学习,你就能得到答案。
4.2.1 泛型的作用
在Dart中,使用泛型的两个目的:第一,简化相同的逻辑;第二,限制可使用的类型。下面我们结合实际的案例来体会上述两点。现在,有这样一个需求:使用星号(*)打印如下所示的实心直角三角形。

当然,建议你先自己尝试。具体算法实现如下所示:

4.2.2 泛型的使用示例
对于上例,如果考虑使用加号(+)、减号(-)等情况,难道就要写一堆printTriangle()方法吗?当然不用,仅需对上述代码稍加修改就可满足多种需求。参考如下代码:

运行后的输出结果依然是由星号组成的直角三角形。当需要用加号或其他字符来拼这个三角形时,只需要更改调用它的位置的参数就可以了。在上述代码中,我们用T取代String来充当类型占位符。这是一个典型的泛型的应用。
4.2.3 限制泛型类型范围
我们发现,在上例的代码中char类型被强制转换成了String类型。这一操作存在风险,如果传入的参数是一个数字,就会出现类型相关的异常:


因此,为了保证程序的正常运行,就要限制传入的类型仅为String。限制泛型的类型要用extends关键字,具体方法如下:

可以看到,代码第一行改成了Textends String,此处的char类型也无须转换成String类型。此时,如果在调用它的位置传入了非String类型的变量,就会出现编译错误而无法运行,杜绝了在运行时异常的发生。
4.2.4 使用泛型方法
在Dart的早期版本中,泛型只能在类上使用。目前,Dart已经支持在方法上使用泛型了。上例中,printUseChar()方法无返回值,如果想得到输出的字符串,而不是单纯地只在这个方法中输出到控制台,就需要返回整个字符串,代码如下:


在这段代码中,泛型作为返回值用在了方法上。由于我们之前限制了类型范围,因此,此处返回的依然是String类型,strForPrint变量保存了输出的字符串的值。