Dart-Generics

1. 泛型概述

泛型(Generics)允许我们在类、方法和接口中使用占位符来代表类型,使代码在不同类型间具有更好的通用性和重用性。Dart 使用 <...> 语法标记泛型类型。

2. 泛型类型的命名

在 Dart 中,泛型类型参数通常使用单个字母来命名,例如 E(元素)、T(类型)、S(类型)、K(键)、V(值)等。

3. 为什么使用泛型?

3.1 类型安全

泛型提供类型安全,通过在编译时强制类型检查,避免了运行时的类型错误。例如,如果我们打算创建一个只包含字符串的列表,可以声明为 List<String>,这样就可以在编译时检测到向列表中添加非字符串的错误。

var names = <String>[];
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // 错误:类型不匹配

3.2 减少代码重复

泛型允许在多个类型之间共享同一个接口和实现,从而减少代码重复。例如,我们可以使用泛型创建一个通用的缓存接口,而不是为每种类型单独创建接口

abstract class Cache<T> {
  T getByKey(String key);
  void setByKey(String key, T value);
}

4. 泛型的使用

4.1 泛型类

定义泛型类时,可以在类名后面加上类型参数

class Box<T> {
  T? value;

  Box(this.value);

  void showValue() {
    print(value);
  }
}

void main() {
  var intBox = Box<int>(123);
  intBox.showValue(); // 输出: 123

  var stringBox = Box<String>("Hello");
  stringBox.showValue(); // 输出: Hello
}

4.2 泛型方法

定义泛型方法时,可以在方法名之前加上类型参数。

T getFirst<T>(List<T> items) {
  return items[0];
}

void main() {
  var numbers = [1, 2, 3];
  var firstNumber = getFirst(numbers); // 类型推断为 int
  print(firstNumber); // 输出: 1

  var words = ["apple", "banana", "cherry"];
  var firstWord = getFirst(words); // 类型推断为 String
  print(firstWord); // 输出: apple
}

4.3 使用集合字面量

可以使用带有类型参数的集合字面量,例如列表、集合和映射。

var names = <String>['Seth', 'Kathy', 'Lars'];
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
  'index.html': 'Homepage',
  'robots.txt': 'Hints for web robots',
  'humans.txt': 'We are people, not machines'
};

4.4 构造函数中的泛型类型

使用构造函数时,可以在类名后面指定泛型类型。

var nameSet = Set<String>.from(names);

var views = Map<int, View>();

5. 泛型集合和类型信息

Dart 的泛型类型是具体化的(reified),这意味着它们在运行时携带类型信息。

var names = <String>[];
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // 输出: true

6. 限制参数化类型

在实现泛型类型时,可能需要限制参数类型。例如,确保类型是非空的,可以使用 extends 关键字。

class Foo<T extends Object> {
  // 提供给 Foo 的 T 类型必须是非空类型
}

class Foo<T extends SomeBaseClass> {
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

void main() {
  var someBaseClassFoo = Foo<SomeBaseClass>();
  var extenderFoo = Foo<Extender>();
  var foo = Foo();
  print(foo); // 输出: Instance of 'Foo<SomeBaseClass>'
}

7. 泛型方法

方法和函数也可以使用类型参数。

T first<T>(List<T> ts) {
  T tmp = ts[0];
  return tmp;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容