3.7 泛型 – 《简单易懂的Dart》

3.7.1 使用泛型

Dart的变量类型是可省的,所以在类型约束方面很松散.

在一些场合我们仍然需要对类型进行约束,这个时候就需要用到泛型了.

Dart的List类就支持泛型,默认情况下,List类的实例中可以放入所有可能的类型,就像这样:

void main(){  
  var list=new List();
  list.add(123);
  list.add(true);
  list.add({'123':123});
  print(list);
}

输出结果为

[123, true, {123: 123}]

在这个list变量中,依次存入了num类型,bool类型,Map类型的值.

假设当前的项目需要两个程序员协作完成,某一个List类型的实例只允许放入String类型的值,最好的解决方案就是使用泛型.

举个例子,这个List实例是用来存储书籍名称的,如果存入的是非String类型的值,在其他环节调用的时候就可能会出错,所以要在数值被存入该函数的时候就进行类型检查,避免异常的发生.

在Dart中使用泛型十分简单,在<>符号中指定类型即可,例如指定String类型,就用,如果需要指定多个泛型用逗号隔开即可.

void main(){  
  var books=new List<String>();
  books.add('《算法导论》');
  books.add('《编译原理》');
  books.forEach((s)=>print(s));
}

输出结果为

《算法导论》
《编译原理》

尝试使用add方法加入其他类型的值时则会报错:

Unhandled exception:  
type '*****' is not a subtype of type 'String' of 'value'.  

3.7.2 定义泛型

定义泛型和使用泛型的差别不大,也使用<>符号.

class TypeList<T>{  
  List list=new List();

  add(T value){
    list.add(value);
  }

  T operator [](int i){
    return list[i];
  }

  forEach(f)=>list.forEach(f);
}

void main(){  
  var books=new TypeList<String>();
  books.add('《算法导论》');
  books.add('《编译原理》');
  books.forEach((s)=>print(s));
}

在这段代码中,我们在类的开头使用定义了类型(Type),并且实现了add方法,重载了[]运算符,模拟了forEach方法.

代码中的T就是该泛型类型,在类实例化时将被制定其类型,而T仅仅是作为一个编译期的别名存在.

TypeList较之3.7.1中的List的优点在于原始数据以不限制类型的List变量存在,以便在特殊情况中将List脱离泛型约束.

3.7.3 关于E, T, K, V

E, T, K, V是泛型中常用的几个名称,实际上定义泛型时完全可以不使用它们.

不过这几个字母用得人多了,也就有了可读性上的意义,这样可以更好的进行协作.

E代表Element,元素.

T代表Type,类型.

K代表Key,键.

V代表Value,值.