Dart(2.2) - 泛型(Generics)

泛型(Generics)

如果你在API文档寻找基本数组类型或者 List 类型,你将会看到该类型实际上为List,其中<...>标记表示此表为一个泛型类型(或为参数化结构)—— 一种含有正规类型参数的类型。按照惯例,类型变量通常为单字符名称,例如E,T,S,K,以及V。

为何要使用泛型?

泛型经常是被要求类型安全的,而且还有很多优势:

  • 合理的指定泛型类型能够更好的生成代码
  • 使用泛型减少重复代码

如果你打算使用一个仅仅包含字符串的List,你可以声明它为List,通过这种方式,你的程序员同事,以及你的工具(比如Dart编辑器和调试模式下的Dart虚拟机)能检测到将一个非字符串的变量分配到List中很可能是错误的,这里给出一个样例:

var names = List();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error

另外一个使用泛型的原因是减少重复的代码。 泛型可以在多种类型之间定义同一个实现, 同时还可以继续使用检查模式和静态分析工具提供的代码分析功能。 例如,你创建一个保存缓存对象的接口:

abstract class ObjectCache {
  Object getByKey(String key);
  void setByKey(String key, Object value);
}

后来你发现你需要一个用来缓存字符串的实现, 则你又定义另外一个接口:

abstract class StringCache {
  String getByKey(String key);
  void setByKey(String key, String value);
}

然后,你又需要一个用来缓存数字的实现, 在后来,你又需要另外一个类型的缓存实现,等等。。。

泛型可以避免这种重复的代码。 你只需要创建一个接口即可:

abstract class Cache {
  T getByKey(String key);
  void setByKey(String key, T value);
}

在上面的代码中,T 是一个替代类型。这是一个类型占位符, 在开发者调用该接口的时候会指定具体类型。

使用集合字面量

Listset以及map都能被参数化,参数字面量就像你已经见过的常量那样,除非你在左方括号之前添加(对于List)或者(对于map)。这里有一个使用常量类型的例子:

var names = ['Seth', 'Kathy', 'Lars'];
var uniqueNames = {'Seth', 'Kathy', 'Lars'};
var pages = {
  'index.html': 'Homepage',
  'robots.txt': 'Hints for web robots',
  'humans.txt': 'We are people, not machines'
};

使用带构造器的参数化类型

为了在使用构造器时详细说明一个或多个类型,将类型放入类名后的三角括号(<...>)中,举个例子:

var nameSet = Set.from(names);

下列代码创建了一个含有整型的键以及值为View的map:

var views = new Map();

泛型集合及其包含的类型

Dart泛型类型是被具体化的,意思就是它们在整个运行时间中都携带着类型信息。举个例子,你可以测试一个集合中的类型甚至是在生产模式中:

var names = List();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List); // true

限制泛型类型

当使用泛型类型的时候,你可能想限制泛型的具体类型。 使用extends可以实现这个功能:

class Foo {
  // Implementation goes here...
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

使用SomeBaseClass或子类作为泛型类型

var someBaseClassFoo = Foo();
var extenderFoo = Foo();

不指定泛型类型也是可以的

var foo = Foo();
print(foo); // Instance of 'Foo'

如果指定非SomeBaseClass类型将报错

var foo = Foo(); // error

使用泛型函数

一开始,泛型只能在Dart类中使用。 新的语法也支持在函数和方法上使用泛型了

T first(List ts) {
  // Do some initial work or error checking, then...
  T tmp = ts[0];
  // Do some additional checking or processing...
  return tmp;
}

这里的 first ()泛型可以在如下地方使用参数 T :

  • 函数的返回值类型 (T)
  • 参数的类型 (List)
  • 局部变量的类型 (T tmp)

参考

Dart

你可能感兴趣的:(Dart(2.2) - 泛型(Generics))