Java开发过程中,会通过重载实现根据不同的参数类型生成类似方法(多态),进一步可以通过 泛型 进一步提取基类方法;而对于 Dart 而言,为了解决多种方式构造对象的场景,也可以通过 Dart 中的 Generics 泛型 来提取基类。

Generics

Generics 泛型是用于解决 类/接口/方法 复用性以及对不特定类型进行数据校验的一种方式;通常用 <…> 符号表示,其中参数一般用 T、E、S、K、V 字母代表;

泛型优势

Dart 不支持重载,所以可以通过设置多个不同名称的方法或不同的命名构造函数以用来区分不同功能的实现。

bool getBoolValue(bool value) {}
bool saveIntValue(int value) {}
String saveStringValue(String value) {}

上面代码设置多个类似的方法,可见代码过于冗余;不过Dart 中的类型实际是可选的,即在 Dart 中函数类型,可以省略参数类型和变量类型等;
因此也可以尝试不指定传参类型和返回类型,这样可以避免代码冗余,但是却放弃了代码检查;

getValue(value) => value;

此时,我们可以考虑用 泛型 方式来处理,而泛型的优势就是适当地指定泛型可以更好地帮助代码生成和减少代码冗余;

T getValue<T>(T value) => value;print('SpUtils -> getValue(bool) -> ${getValue(true)} -> ${getValue<bool>(true)}');
print('SpUtils -> getValue(int) -> ${getValue(123)} -> ${getValue<int>(1)}');
print('SpUtils -> getValue(String) -> ${getValue('dart泛型')} -> ${getValue<String>('dart泛型')}');

泛型方法

上述代码中定义了一个 getValue 的泛型方法,但是泛型的应用比较灵活,可以只限制参数或返回类型或两者均限制。

  1. 函数参数为泛型类型
    getValue() 可以当作一个普通的函数使用,但是为了限制参数类型校验,可以在参数前加入固定类型;因为限制了 getValue 因此参数只能传递 String 类型,若传入其他类型参数则会异常提示;
getValue<T>(T value) => value;
print('${getValue<String>('dart泛型')}');
// 异常参数类型 getValue<String>(123)
// The argument type int can’t be assigned to the parameter type String.
  1. 函数返回值为泛型类型
    getValue() 前添加泛型限制时,即限制了返回参数为泛型类型,其中的返回内容不能限制为固定的某一种类型,此时参数和返回值均会进行不确定类型校验;
T getValue<T>(T value) => value;
print('${getValue<String>('dart泛型')}');

泛型类

Dart 中常用的 List 或 Set 等基础数组类型均为泛型类;下面以 List 为例,创建了一个 MList 的泛型类;

class MList<T> {List _list = List<T>();void add<T>(T value) {this._list.add(value);}get myList => this._list;
}

这样不限制类型,可以在 MList 中添加任意类型的数据;当限制传入数据为 int 或 String 类型时,则只能传入固定类型数据,否则会异常提示;即通过泛型对不确定类型进行了数据校验;

MList mList1 = MyList();
mList1.add(true);
mList1.add(123);
mList1.add('dart泛型');
print('MList -> ${mList1.mList}');

输出:

I/flutter (13297): MyList -> [true, 123, dart泛型]

MList mList2 = MList<int>();
mList2.add(true);  // 只能传入固定 int 类型
mList2.add(123);
print('MList -> ${mList2.mList}');

输出:

type ‘bool’ is not a subtype of type ‘int’ of ‘value’

泛型接口

Dart 中定义泛型接口和泛型类是一样的,Dart 中定义接口方式可以是普通类也可以是抽象类;定义一个 Sp 接口,添加了 get / set 方法;

abstract class Sp<T> {void set(String key, T value);T get(String key);
}class SpUtils<T> implements Sp<T> {Map map = new Map();@overrideT get(String key) {return map[key];}@overridevoid set(String key, T value) {map[key] = value;}
}

使用时与泛型类一致,在不限制 set 类型时,可以是任意数据类型,而若设置 SpUtils 时,则限制 set 内容只能为 String 类型,若传入其他类型则会异常提示。

SpUtils spUtils = SpUtils();
spUtils.set('name', '张三');
spUtils.set('age', 10);
print('SpUtils -> ${spUtils.get('name')} -> ${spUtils.get('age')}');/// I/flutter (13297): SpUtils -> dart泛型 -> 10SpUtils spUtils2 = SpUtils<String>();
spUtils2.set('name', '张三');
spUtils2.set('age', 10);    // 只能传入固定 String 类型
print('SpUtils -> ${spUtils2.get('name')} -> ${spUtils2.get('age')}');/// type 'int' is not a subtype of type 'String' of 'value'

泛型约束

在使用泛型类型时可以限制其参数类型,例如,可以使用 extends 在进行限制;通过 extends 可以限制其当前参数类型及其子类参数类型;

class Animal {}
class FlyAnimal extends Animal {}
class LandAnimal extends Animal {}
class Bird extends FlyAnimal {}
class Dog extends LandAnimal {}
class Cat extends LandAnimal {}
class Foo<T extends LandAnimal> {}Foo foo1 = Foo<LandAnimal>();
Foo foo2 = Foo<Cat>();
Foo foo3 = Foo<Dog>();
Foo foo4 = Foo<FlyAnimal>();  /// 异常类型;

这里对 泛型 理解仅限于日常应用,对于 协变 / 逆变 等理解并未详细介绍;由于个人水平有限,如有错误,请多多指教!

Dart基础之Generics 泛型 <T>相关推荐

  1. TS基础2(泛型、枚举、元组)-学习笔记

    文章目录 TS基础2(泛型.枚举.元组)-学习笔记 泛型 枚举 元组 例子参考 TS基础2(泛型.枚举.元组)-学习笔记 泛型 //泛型(Generics)是指在定义函数.接口或类的时候,不预先指定具 ...

  2. Pascal基础(七)-Pascal泛型

    Pascal基础(七)-Pascal泛型 前言 目前很多语言都有泛型或者类似实现 C语言比较古老,没有泛型实现 C++ 有template来实现,个人对c++不懂,应该template和泛型不一样 j ...

  3. Dart基础学习02--变量及内置类型

    Dart基础学习02--变量及内置类型 Dart中的变量 首先看一个变量的定义和赋值 var name = 'Bob'; 在Dart中变量名都是引用,这里的name就是一个指向值为Bob的字符串的引用 ...

  4. Dart基础知识之main()函数介绍

    Dart基础知识之main()函数介绍 main()函数 main()函数,这是一种特殊的.必需的顶级函数,应用程序从这里开始执行(重要)!!! print()函数 显示输出,把内容显示在屏幕上 字符 ...

  5. Dart入门—库、泛型与异常

    Dart入门-库.泛型与异常 库 Pub仓库 在Pub上可以下载到支持各种功能的包,首页在根目录下建立pubspec.yaml文件 name: test_app dependencies:sqljoc ...

  6. Dart基础语言 — Runes

    Dart基础语言 - Runes Runes Runes 对象是一个 32位 字符对象,用来表示一个字. 这样设计也是考虑兼容 UTF-16 四个字节的情况. length 和 runes.lengt ...

  7. Flutter的优势以及Dart基础语法

    1.为什么要学习Flutter? 对于移动端开发人员来说,跨平台技术一直是关注的重点,从H5,React Native到Flutter,我们似乎一直在寻找一种能"一套代码,多端运行" ...

  8. Java基础系列12: 泛型

    Java基础系列12: 泛型 本文是作者的读书笔记和心得整理,部分内容来源于网络,如有侵权,请联系作者. 什么是泛型 直接看例子 List arrayList = new ArrayList(); a ...

  9. C# Generics 泛型

    C# Generics 泛型 泛型优点 性能 为了让方法传递任何类型的参数,可以用object类来传递参数.值类型转换为引用类型称为装箱,引用类型转换为值类型称为拆箱,需要强制转换.如下代码所示: 数 ...

最新文章

  1. pythonl学习笔记——爬虫的基本常识
  2. moment 当前日期
  3. 线程的状态 Thread.State||NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED
  4. 10万人的大场馆如何“画座位”?
  5. P2801-教主的魔法【分块,二分】
  6. 抓娃娃机爪不动怎么办_黄子韬吃娃娃菜能把临时牙咬断?种植牙到底结实不结实?...
  7. 网络IO模型详细分析
  8. 为什么hbase里没有表会显示表已经存在_0712-6.2.0-HBase快照异常
  9. java poi打印word_Java 打印Word文档
  10. pandas 链接数据库
  11. linux get current thread count and system threads limit
  12. 如何以源码安装mysql_CentOS以源码方式安装MySQL
  13. 喵哈哈村与哗啦啦村的大战(四)(树形DP)
  14. Linux 字符设备驱动及一些简单的Linux知识
  15. oracle建表语句 货币,Oracle建表语句是什么
  16. 不一样的设计!20个国外优秀的电子商务网站
  17. 蜗牛星际改内存_蜗牛星际再次升级为800多元的变种蜗牛:G5400+B365的双千兆网口做NAS香吗...
  18. Android自定义view之围棋动画,kotlin实现接口
  19. FPS游戏的方框透视+自瞄原理
  20. Win7,Win10电脑内显示文件后缀(扩展名)的方法

热门文章

  1. 5W无线充SOC方案芯片 封装SOP16和SOP8
  2. 【C++】挖金子(黄金矿工)分析与代码实现
  3. 曾红过那英,巅峰时却远嫁日本,
  4. PHP最新B站视频直链解析源码下载+亲测可用
  5. Teams升级选项中的后台自动下载安装Teams客户端--Download Teams App in the background
  6. 测试一下文章行内代码的显示
  7. [爆笑网文]男人都是这副德性
  8. java-net-php-python-jsp桂林母婴用品二手交易网计算机毕业设计程序
  9. 流媒体技术------Java实现调用本地摄像头
  10. DGP链游公会首发合作项目——D.G.Pals