【Dart 专题】Generics 泛型 <T>

简介: 0 基础学习 Dart 语言,简单了解泛型应用!

    小菜在 Android 开发过程中,会通过重载实现根据不同的参数类型生成类似方法,进一步可以通过 泛型 进一步提取基类方法;而对于 Dart 而言,为了解决多种方式构造对象的场景,也可以通过 泛型 来提取基类;今天小菜简单学习一下 Dart 中的 Generics 泛型;

// Android 
public static void getValue(boolean value) {}

public static void getValue(int value) {}

public static void getValue(long value) {}

public static void getValue(String value) {}

Generics

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

泛型优势

    小菜为实现上述 Java 对应传递固定类型参数返回固定类型方法,因 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>(123)}');
print('SpUtils -> getValue(String) -> ${getValue('阿策小和尚')} -> ${getValue<String>('阿策小和尚')}');

泛型方法

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

1. 函数参数为泛型类型

    getValue() 可以当作一个普通的函数使用,但是为了限制参数类型校验,可以在参数前加入固定类型;因为限制了 getValue 因此参数只能传递 String 类型,若传入其他类型参数则会异常提示;

getValue<T>(T value) => value;

print('SpUtils -> getValue(String) -> ${getValue<String>('阿策小和尚')}');

// 异常参数类型 getValue<String>(123)
// The argument type int can’t be assigned to the parameter type String.

2. 函数返回值为泛型类型

    getValue() 前添加泛型限制时,即限制了返回参数为泛型类型,其中的返回内容不能限制为固定的某一种类型,此时参数和返回值均会进行不确定类型校验;

T getValue<T>(T value) => value;

print('SpUtils -> getValue(String) -> ${getValue<String>('阿策小和尚')}');

泛型类

    Dart 中常用的 ListSet 等基础数组类型均为泛型类;小菜以 List 为例,创建了一个 MyList 的泛型类;

class MyList<T> {
  List _list = List<T>();

  void add<T>(T value) {
    this._list.add(value);
  }

  get myList => this._list;
}

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

MyList myList1 = MyList();
myList1.add(true);
myList1.add(123);
myList1.add('阿策小和尚');
print('MyList -> ${myList1.myList}');

/// I/flutter (13273): MyList -> [true, 123, 阿策小和尚]

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

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

  @override
  T get(String key) {
    return map[key];
  }

  @override
  void set(String key, T value) {
    map[key] = value;
  }
}

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

SpUtils spUtils = SpUtils();
spUtils.set('name', '阿策小和尚');
spUtils.set('age', 18);
print('SpUtils -> ${spUtils.get('name')} -> ${spUtils.get('age')}');

/// I/flutter (13273): SpUtils -> 阿策小和尚 -> 18

SpUtils spUtils2 = SpUtils<String>();
spUtils2.set('name', '阿策小和尚');
spUtils2.set('age', 18);    // 只能传入固定 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>();  /// 异常类型;

    小菜对 泛型 理解仅限于日常应用,对于 协变 / 逆变 等理解还不到位;如有错误,请多多指导!

来源: 阿策小和尚

相关文章
|
存储 缓存 IDE
VirtualBox实现共享剪贴板
VirtualBox实现共享剪贴板
1531 0
|
监控 网络协议 Java
Jmeter系列(35)- 使用 ServerAgent 监控服务器
Jmeter系列(35)- 使用 ServerAgent 监控服务器
1305 0
Jmeter系列(35)- 使用 ServerAgent 监控服务器
|
11月前
|
前端开发 开发工具 Android开发
小红书APP的全新鸿蒙NEXT端性能优化技术实践
从 2023 年开始,鸿蒙的优势愈发明显,已经成为可与 iOS、安卓媲美的第三大移动操作系统。从一些抖音视频中也可以看出,鸿蒙在流畅性方面甚至在某些层面上超过了 iOS。本次分享的主题是小红书在鸿蒙平台上的工程实践,主要聚焦于性能优化和探索。
802 10
|
12月前
|
JSON 监控 JavaScript
Swagger UI 本地主机教程: 如何在本地使用 Swagger UI?
Swagger UI 提供在线和离线版本,但由于各种原因,你可能需要在本地使用 Swagger UI。 在本文中,我们将向你展示如何在本地使用 Swagger UI。
|
缓存 前端开发 JavaScript
Webpack 4 和 Webpack 5 区别?
【10月更文挑战第23天】随着时间的推移,Webpack 可能会继续发展和演进,未来的版本可能会带来更多的新特性和改进。保持对技术发展的关注和学习,将有助于我们更好地应对不断变化的前端开发环境。
|
小程序 Java 关系型数据库
微信记账小程序
微信记账小程序
949 0
|
NoSQL 安全 Java
Redis从入门到精通之Lua 脚本
Lua 是一种轻量级的脚本语言,被广泛应用于游戏开发、嵌入式系统、Web 开发、科学计算等领域。Redis 内置了 Lua 解释器,使得用户可以通过编写 Lua 脚本来扩展 Redis 的功能。在 Redis 中,可以使用 EVAL 和 EVALSHA 命令执行 Lua 脚本。
1257 109
Redis从入门到精通之Lua 脚本
|
数据采集 数据可视化 大数据
【优秀python大屏案例】基于python flask的前程无忧大数据岗位分析可视化大屏设计与实现
本文介绍了一个基于Python Flask框架的前程无忧大数据岗位分析可视化大屏系统,该系统通过爬虫技术采集招聘数据,利用机器学习算法进行分析,并以可视化大屏展示,旨在提高招聘市场数据分析的效率和准确性,为企业提供招聘决策支持和求职者职业规划参考。
827 2
|
缓存 安全 Unix
深入探索Linux中的qemu-ga命令
**QEMU的qemu-ga是虚拟机内的守护进程,提供带外通道管理guest OS,如文件操作、关机、休眠等。它通过virtio-serial通信,特点是安全、高效、灵活。例如,使用`virsh qemu-agent-command`执行虚拟机内部命令。最佳实践包括安装配置agent、设置黑名单、考虑安全和性能、定期备份及利用社区资源。**