您的位置:

Dart泛型详解

一、Dart泛型概述

在 Dart 语言中,泛型是指一个类或方法可以接受不同类型的参数。泛型可以帮助我们更好地封装代码,提高代码的可重用性和安全性。

泛型的基本语法如下:


class ClassName<T> {
  T method(T arg) {
    return arg;
  }
}

其中,<T> 表示泛型类型参数,可以是任何合法的 Dart 标识符。在上面的例子中,我们定义了一个泛型类 ClassName,它有一个泛型方法 method,该方法接受一个泛型参数 arg,并返回该参数。

二、Dart泛型擦除

Dart 通过泛型擦除来实现泛型。泛型擦除是指编译器在编译时会将泛型的具体类型替换为 Object 类型,并在必要时进行强制转换。这就意味着,在运行时无法判断泛型的类型。

示例代码如下:


void main() {
  List<int> list = [1, 2, 3];
  print(list.runtimeType); // 输出:List<int>
  processList(list);
}

void processList(List<Object> list) {
  print(list.runtimeType); // 输出:List<int>
}

在上面的代码中,我们先定义了一个 List<int> 类型的 list,然后将它作为参数传递给了 processList 方法。在 processList 方法中,我们将参数类型定义为 List<Object>,并输出该参数的类型。我们会发现,输出结果为 List<int>,而不是 List<Object>。这是因为在编译时,泛型类型 int 被擦除,list 的实际类型变为 List<Object>。

三、Dart泛型序列化

Dart 通过序列化和反序列化来实现泛型。序列化是指将对象转换为二进制格式或其他格式,以便于存储或传输。反序列化是指将二进制格式或其他格式转换为对象。

在 Dart 中,我们可以使用 json 库来实现泛型序列化。示例代码如下:


import 'dart:convert';

class Person<T> {
  T name;
  int age;

  Map toJson() {
    return {'name': name, 'age': age};
  }

  static Person fromJson(Map json, T Function(dynamic) fromJsonT) {
    return Person<T>()
        ..name = fromJsonT(json['name'])
        ..age = json['age'];
  }
}

void main() {
  var person = Person<String>()
    ..name = '张三'
    ..age = 18;
  var json = jsonEncode(person.toJson());
  print(json); // 输出:{"name":"张三","age":18}
  var decodedJson = jsonDecode(json);
  var decodedPerson = Person.fromJson(decodedJson, (dynamic name) => name.toString());
  print(decodedPerson.name); // 输出:张三
}

在上面的代码中,我们先定义了一个泛型类 Person,通过 toJson 方法将 Person 实例转换为 Map 对象。然后我们将 Map 对象编码为 JSON 字符串,并输出编码结果。接着,我们将 JSON 字符串解码为 Map 对象,并使用 fromJson 方法将 Map 对象转换为 Person 对象。

四、Dart泛型类型限制

Dart 中可以使用 extends 关键字来限制泛型的类型。示例代码如下:


abstract class Animal {
  String getName();
}

class Cat implements Animal {
  String name;
  
  Cat(this.name);
  
  String getName() => name;
}

class Dog implements Animal {
  String name;
  
  Dog(this.name);
  
  String getName() => name;
}

class AnimalList<T extends Animal> {
  final List<T> _animals = [];
  
  void add(T animal) {
    _animals.add(animal);
  }
  
  void printNames() {
    for (var animal in _animals) {
      print(animal.getName());
    }
  }
}

void main() {
  var animalList = AnimalList<Animal>();
  animalList.add(Cat('小花'));
  animalList.add(Dog('旺财'));
  animalList.printNames(); // 输出:小花 旺财
}

在上面的代码中,我们先定义了一个抽象类 Animal,然后定义了两个实现类 Cat 和 Dog,它们都继承自 Animal。接着,我们定义了一个泛型类 AnimalList,它用于存储 Animal 类型的对象。在 AnimalList 的泛型类型参数 T 上使用 extends 关键字,表示 T 只能是 Animal 或 Animal 的子类。在 AnimalList 类中,我们添加了 add 和 printNames 方法,add 方法用于向 _animals 列表中添加 Animal 类型的对象,printNames 方法用于输出 _animals 中所有对象的名称。

五、Dart泛型类型推断

在 Dart 2.0 中,编译器可以根据变量的类型自动推断泛型类型参数。示例代码如下:


void main() {
  var list = <int>[1, 2, 3];
  var index = 2;
  var item = list[index];
  print(item); // 输出:3
  
  var map = <String, int>{
    'one': 1,
    'two': 2,
    'three': 3
  };
  var key = 'two';
  var value = map[key];
  print(value); // 输出:2
}

在上面的代码中,我们先定义了一个类型为 List<int> 的 list,然后定义了一个变量 index,它的值为 2。接着,我们根据 index 取出了 list 中的第三个元素,并将结果赋值给变量 item。由于 list 的类型已经被推断为 List<int>,所以编译器可以自动推断出 item 的类型为 int。同理,我们定义了一个类型为 Map<String, int> 的 map,然后根据 key 取出了 map 中的一个值,并将结果赋值给变量 value,编译器可以自动推断出 value 的类型为 int。