Flutter圈子

Dart学习-泛型

2018-10-23  本文已影响20人  你需要一台永动机
Dart

如果在API文档上查看基本数组类型List,你会发现该类型实际上是List<E> ,其中<...>注解标记这次集合是一个泛型(参数化的)类 -->一种含有正规类型参数的类型。按照惯例,类型变量通常为单字符名称,例如E,T,S,K,以及V。


为何要使用泛型?

类型安全通常需要泛型,但是它们比仅仅允许代码运行有更多的好处:

如果你希望列表仅包含字符串,则可以将其声明为List<String> (将其称为“字符串列表”)。这样,你、你的同事和你的工具就可以发现给列表分配一个非字符串是错误的。这里有一个例子:

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

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

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是代理类型。这是一个占位符,你可以将其视为稍后将定义的类型。


使用集合常量

Lis常量以及map常量都能被参数化。参数常量就像你已经见过的常量那样,除非你在左方括号之前添加<type>(对于List)或者<keyType,valuetype>(对于map)。以下是使用类型化常量的示例:

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);

接下来的代码创建一个map,key为Interger类型,value为View类型

var views = Map<int, View>();

泛型集合及其包含的类型

dart泛型类型被具体化,这意味着它们在运行时携带它们的类型信息。例如,你可以测试集合的类型:

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

注:相反,Java中的泛型使用擦除,这意味着在运行时移除泛型类型参数。在Java中,你可以测试对象是否是列表,但不能测试它是否是List<String>


限制参数化类型

实现泛型类型时,你可能希望限制其参数的类型。你可以使用extens来执行此操作。

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的一般支持仅限于类。一种称为泛型方法的较新语法允许对方法和函数进行类型参数:

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

这里,first(<T>)上的泛型类型参数允许你在几个地方使用类型参数T :

PS:本文整理自官方文档,若有发现问题请致邮 caoyanglee92@gmail.com

上一篇 下一篇

猜你喜欢

热点阅读