Dart之旅08: 范型

2019-02-13  本文已影响0人  suikaJY

如果你查阅List类的API文档,你会看见类型的写法是List<E>这里的E就是范型,它指代这个类型的实例是某种类型相关的。

为什么使用范型?

范型通常用来保证类型安全,并且他还有更多的好处是你的代码运行:

使用范型可以让工具检测出更多书写错误:

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

另一个使用原因是可以减少代码重复,比如你想实现一个对象缓存:

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

你会发现你经常能用到字符串缓存,或者Int缓存,所以你又照着原有代码定义了个StringCache或者IntCache之类的:

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只是一个占位符,当你真正声明Cache对象的时候需要指明T所指代的类型。

使用集合字面量

集合字面量期望你添加明确的范型:

var names = <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 names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
var nameSet = Set<String>.from(names);

或者非命名构造函数:

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>

范型限制

和Java类似,限制范型的范围的方式可以使用extends关键字:

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

class Extender extends SomeBaseClass {...}

这时你就只可以使用SomeBaseClass类型或者它的子类当作范型了:

var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();

这时你可以指定没有范型的Foo,它的范型默认是SomeBaseClass:

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

你不可以指定非SomeBaseClass的子类,下面的代码不能通过编译:

var foo = Foo<Object>();

使用范型方法

起初,Dart的范型只能使用类级别的范型,后来可以在方法上定义方法级别的范型了。

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

类似Java的范型方法,这里定义T时需要在方法名之后定义一个新的范型变量。它有三种用途:

更多信息参考使用范型方法

上一篇 下一篇

猜你喜欢

热点阅读