【Flutter 基础】 泛型

2021-07-15 16:05:44 浏览数 (1)

当我们查看 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": {}
}

每一个接口都会返回 codemsgdata 为业务数据,可以每一个接口返回的实体类型都进行如下定义:

代码语言:javascript复制
class Data1{
  String code;
  String msg;
  dynamic data;
}

这是每一个实体类型都会包含codemsg字段,我们可以使用泛型去掉重复代码:

代码语言: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

FutureStream 使用泛型,是异步泛型,返回指定类型。FutureStream 完成的时候要么返回指定的类型值要么返回异常。

比如 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源码和第三方插件的源码时泛型随处可见。

0 人点赞