当我们查看 Flutter 源码的时候会发现源码中有大量的 、 代码,比如 List 的源代码
代码语言:javascript复制abstract class List<E> implements EfficientLengthIterable<E> {
<..> 标记表示泛型的概念,通常情况下,泛型使用单字母表示,比如:E,T,S,K和V。
为什么要使用泛型?它有什么作用?
在编译阶段进行类型安全检查
一个重要的作用是泛型会在编译阶段进行类型安全检查,比如有一个 String 类型集合:
代码语言:javascript复制List<String> list = [];
list 是一个String类型的集合,list 中的元素必须是String类型,添加其他类型时编译阶段报错
代码语言:javascript复制list.add(1); //编译不通过
假设不使用泛型,定一个集合:
代码语言:javascript复制List list1 = [];
list1 中可以添加任意类型的数据:
代码语言:javascript复制list1.add('value');
list1.add(1);
编译都可以通过,list1 等价于如下的定义:
代码语言:javascript复制List<dynamic> list1 = [];
减少重复代码
泛型可以有效的减少重复代码,一个典型使用场景:服务端返回的接口通常是统一的格式,比如返回如下json格式:
代码语言:javascript复制{
"code": 0,
"msg": "",
"data": {}
}
每一个接口都会返回 code 和 msg,data 为业务数据,可以每一个接口返回的实体类型都进行如下定义:
代码语言:javascript复制class Data1{
String code;
String msg;
dynamic data;
}
这是每一个实体类型都会包含code 和 msg字段,我们可以使用泛型去掉重复代码:
代码语言:javascript复制class DataBase<T>{
String code;
String msg;
T data;
}
class Person {
String name;
Person(this.name);
}
使用:
代码语言:javascript复制var data = DataBase<Person>();
List Map Future Stream 使用泛型
在实际开发中,泛型几乎无处不在,下面介绍几个常用的场景。
List指定集合元素类型:
代码语言:javascript复制List<int> list = [];
list.add(1);
list集合指定的类型为 int,只能添加 int 类型数据。
Map<K, V> 指定key、value的类型:
代码语言:javascript复制Map<String,int> map = {'key':1,'key1':2};
map 指定key的类型为 String,value的类型为 int。
Future 和 Stream 使用泛型,是异步泛型,返回指定类型。Future 和 Stream 完成的时候要么返回指定的类型值要么返回异常。
比如 Future 返回一个 String 类型:
代码语言:javascript复制Future<String> fun3() {
return Future.value('flutter');
}
Stream 使用泛型:
代码语言:javascript复制var streamController = StreamController<String>.broadcast();
Stream<String> get data => streamController.stream;
限制泛型
限制泛型并不是不使用泛型,而是对泛型的类型进行限制,使用 extends 关键字:
定义一个基类:
代码语言:javascript复制class DataBase{}
定义 Data 类,此类的泛型需要是DataBase或者其子类:
代码语言:javascript复制class Data <T extends DataBase>{}
这里指定了 T 集成 DataBase。
定义DataBase子类Person:
代码语言:javascript复制class Person extends DataBase{
String name;
Person(this.name);
}
那么如下用法是正确的:
代码语言:javascript复制var data = Data<Person>();
var data1 = Data<DataBase>();
但是下面的用法是错误的:
代码语言:javascript复制var data2 = Data<String>(); //error
class Person1{}
var data3 = Data<Person1>();//error
方法中使用泛型
定义如下方法:获取集合中第2个元素值,集合中元素值为任意类型:
代码语言:javascript复制class Data<T> {
T getSecond(List<T> list) {
return list[1];
}
}
在类中使用泛型
代码语言:javascript复制class DataBase<T> {
T _data;
T getData(){
return _data;
}
}
泛型是非常重要的概念,尤其是写插件和框架的时候。当查看Flutter源码和第三方插件的源码时泛型随处可见。