Dart基础之泛型

前言

若是你查过基本数组类型 List 的API文档,会看到该类型其实是List<E><...>表示法将List标记为通用(或参数化)类型 - 具备正式类型参数的类型。 按照惯例,大多数类型变量都有单字母名称,例如E,T,S,K和V.html

为何要用泛型

泛型的时候经常须要类型安全,但他们相比直接运行代码会有更多的好处:git

  • 正确指定泛型类型会产生更好的生成代码。(对于写代码而言)
  • 你可使用泛型来减小代码重复。

若是你但愿List只包含String,则能够将其声明为List <String>(将其称为“字符串列表”)。 这样,你,你的伙伴和你的工具,能够明白将非字符串分配给列表多是一个错误。 举个例子:github

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // 静态解析的时候就会提示错误
复制代码

使用泛型的另外一个缘由是减小重复代码。 泛型容许你在 多种类型之间共享单个接口和实现,同时仍然利用静态分析。 例如,假设你建立了一个用于缓存对象的接口:web

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> {
  T getByKey(String key);
  void setByKey(String key, T value);
}
复制代码

在此代码中,T是替身类型。 它是一个占位符,你能够将其视为开发人员稍后定义的类型。函数

使用集合文字

能够参数化List,Set 和 Map。 参数化文字就像你已经看到的文字同样,除了你在开始括号以前添加<type>(对于List和Set)或<keyType,valueType>(对于maps)。 如下是使用类型文字的示例:工具

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

使用带有构造函数的参数化类型

要在使用构造函数时指定一个或多个类型,请将类型放在尖括号(<...>)后面的类名称以后。 例如:测试

var nameSet = Set<String>.from(names);
复制代码

如下代码建立一个具备整数键和View类型值的map:

var views = Map<int, View>();
复制代码

通用集合及其包含的类型

Dart泛型类型被定义,这意味着它们在运行时携带它们的类型信息。 例如,你能够测试集合的类型:

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
复制代码

注意:相反,Java中的泛型使用擦除,这意味着在运行时删除泛型类型参数。 在Java中,你能够测试对象是否为List,但没法测试它是否为List<String>

限制参数化类型

实现泛型类型时,你可能但愿限制其参数的类型。 你可使用extends来执行此操做。

class Foo<T extends SomeBaseClass> {
  // 在这里实现
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}
复制代码

可使用SomeBaseClass或其任何子类做为通用参数:

var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
复制代码

也能够不指定泛型参数:

var foo = Foo();
print(foo); //'Foo<SomeBaseClass>'的实例 
复制代码

指定任何非SomeBaseClass类型会致使错误:

var foo = Foo<Object>();//静态解析报错
复制代码

使用泛型方法

最初,Dart的泛型支持仅限于classes。 一种称新的语法称为泛型方法,容许在方法和函数上使用类型参数:

T first<T>(List<T> ts) {
  // 作一些初始化工做或者检查错误...
  T tmp = ts[0];
  // 作一些额外的检查或者处理...
  return tmp;
}
复制代码

这里,first(<T>)上的泛型类型参数容许你在多处使用类型参数T

  • 在函数的返回类型(T)中。
  • 在参数的类型(List<T>)中。
  • 在局部变量的类型(T tmp)。

更多关于泛型的信息,请查看运用泛型方法

相关文章
相关标签/搜索