在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

作者:付文龙(红目香薰)
仓库地址https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git
联系邮箱:372699828@qq.com


一、泛型概述

泛型是一种编程范式,允许在定义函数、类或接口时使用类型参数,从而实现代码的复用和类型安全。在Dart中,泛型是一项核心特性,广泛应用于集合类、状态管理和数据处理等场景。

1.1 为什么需要泛型

在没有泛型之前,我们需要为不同类型重复编写相似的代码:

// 处理整数列表
int findFirstInt(List<int> list, bool Function(int) predicate) {
  for (int item in list) {
    if (predicate(item)) {
      return item;
    }
  }
  throw Exception('未找到');
}

// 处理字符串列表
String findFirstString(List<String> list, bool Function(String) predicate) {
  for (String item in list) {
    if (predicate(item)) {
      return item;
    }
  }
  throw Exception('未找到');
}

使用泛型后,可以将这些代码合并为一个通用函数:

T findFirst<T>(List<T> list, bool Function(T) predicate) {
  for (T item in list) {
    if (predicate(item)) {
      return item;
    }
  }
  throw Exception('未找到');
}

1.2 泛型的优势

优势 说明
代码复用 一份代码可以处理多种类型
类型安全 编译时检查类型,避免运行时错误
性能优化 避免不必要的类型转换
代码清晰 明确表达代码的意图

二、泛型函数

2.1 基本泛型函数

T findFirst<T>(List<T> list, bool Function(T) predicate) {
  for (T item in list) {
    if (predicate(item)) {
      return item;
    }
  }
  throw Exception('未找到匹配项');
}

void main() {
  List<int> numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  int firstEven = findFirst<int>(numbers, (num) => num % 2 == 0);
  print('第一个偶数: $firstEven');  // 输出: 第一个偶数: 2

  List<String> names = ['张三', '李四', '王五', '赵六'];
  String firstWithThreeChars = findFirst<String>(names, (name) => name.length == 3);
  print('第一个三个字的名字: $firstWithThreeChars');  // 输出: 第一个三个字的名字: 张三
}

2.2 泛型函数的类型推断

在很多情况下,Dart可以自动推断泛型类型:

void main() {
  List<int> numbers = [1, 2, 3, 4, 5];
  
  // 显式指定类型
  int result1 = findFirst<int>(numbers, (num) => num > 3);
  
  // 类型推断
  int result2 = findFirst(numbers, (num) => num > 3);
}

2.3 带返回可选值的泛型函数

T? findFirstOrNull<T>(List<T> list, bool Function(T) predicate) {
  for (T item in list) {
    if (predicate(item)) {
      return item;
    }
  }
  return null;
}

void main() {
  List<String> names = ['张三', '李四', '王五'];
  
  String? result = findFirstOrNull<String>(names, (name) => name.length == 4);
  print('查找四个字名字: ${result ?? '未找到'}');  // 输出: 查找四个字名字: 未找到
}

三、泛型类

3.1 基本泛型类

class Container<T> {
  final T value;

  Container({required this.value});
}

void main() {
  Container<int> intContainer = Container<int>(value: 42);
  print('Int容器值: ${intContainer.value}');  // 输出: Int容器值: 42

  Container<String> stringContainer = Container<String>(value: 'Flutter');
  print('String容器值: ${stringContainer.value}');  // 输出: String容器值: Flutter
}

3.2 多类型参数泛型类

class Pair<T, U> {
  final T first;
  final U second;

  Pair({required this.first, required this.second});
}

void main() {
  Pair<String, int> pair = Pair<String, int>(first: '年龄', second: 30);
  print('Pair: ${pair.first} = ${pair.second}');  // 输出: Pair: 年龄 = 30
}

3.3 泛型类的高级用法

class Box<T> {
  List<T> _items = [];

  List<T> get items => _items;
  int get length => _items.length;

  void add(T item) {
    _items.add(item);
  }

  T? get(int index) {
    if (index >= 0 && index < _items.length) {
      return _items[index];
    }
    return null;
  }
}

void main() {
  Box<String> box = Box<String>();
  box.add('Item 1');
  box.add('Item 2');
  box.add('Item 3');
  print('Box内容: ${box.items}');   // 输出: Box内容: [Item 1, Item 2, Item 3]
  print('Box长度: ${box.length}');   // 输出: Box长度: 3
}

四、泛型约束

4.1 类型约束

可以使用extends关键字约束泛型类型:

abstract class Shape {
  double calculateArea();
}

class Circle extends Shape {
  double radius;
  Circle(this.radius);
  
  double calculateArea() => 3.14159 * radius * radius;
}

class Rectangle extends Shape {
  double width;
  double height;
  Rectangle(this.width, this.height);
  
  double calculateArea() => width * height;
}

double calculateArea<T extends Shape>(T shape) {
  return shape.calculateArea();
}

void main() {
  Circle circle = Circle(5);
  Rectangle rectangle = Rectangle(4, 6);

  print('圆形面积: ${calculateArea(circle)}');     // 输出: 圆形面积: 78.53975
  print('矩形面积: ${calculateArea(rectangle)}');  // 输出: 矩形面积: 24.0
}

4.2 数值类型约束

int sumNumbers<T extends num>(List<T> numbers) {
  int sum = 0;
  for (T num in numbers) {
    sum += num.toInt();
  }
  return sum;
}

void main() {
  print('整数列表求和: ${sumNumbers([1, 2, 3, 4, 5])}');   // 输出: 整数列表求和: 15
  print('小数列表求和: ${sumNumbers([1.5, 2.5, 3.5])}');   // 输出: 小数列表求和: 7
}

4.3 多重约束

在Dart中,可以使用&实现多重约束:

class Animal {
  String name;
  Animal(this.name);
}

mixin Flyable {
  void fly() => print('正在飞行');
}

void printNameAndFly<T extends Animal & Flyable>(T animal) {
  print('名字: ${animal.name}');
  animal.fly();
}

class Bird extends Animal with Flyable {
  Bird(String name) : super(name);
}

void main() {
  Bird bird = Bird('麻雀');
  printNameAndFly(bird);
}

五、类型推断

5.1 变量类型推断

Dart可以根据初始化值自动推断变量类型:

void main() {
  var name = '付文龙';
  print('name类型: ${name.runtimeType}');  // 输出: name类型: String

  var age = 30;
  print('age类型: ${age.runtimeType}');    // 输出: age类型: int

  var isOnline = true;
  print('isOnline类型: ${isOnline.runtimeType}');  // 输出: isOnline类型: bool

  var skills = ['Flutter', 'Dart', 'HarmonyOS'];
  print('skills类型: ${skills.runtimeType}');  // 输出: skills类型: List<String>

  var scores = {'张三': 90, '李四': 85};
  print('scores类型: ${scores.runtimeType}');  // 输出: scores类型: _InternalLinkedHashMap<String, int>
}

5.2 集合操作的类型推断

void main() {
  var doubled = [1, 2, 3].map((num) => num * 2);
  print('doubled类型: ${doubled.runtimeType}');  // 输出: doubled类型: MappedListIterable<int, int>

  var filtered = [1, 2, 3, 4, 5].where((num) => num % 2 == 0);
  print('filtered类型: ${filtered.runtimeType}');  // 输出: filtered类型: WhereIterable<int>
}

5.3 泛型类型推断

void main() {
  // 自动推断为List<int>
  var numbers = [1, 2, 3, 4, 5];
  
  // 自动推断泛型类型
  int firstEven = findFirst(numbers, (num) => num % 2 == 0);
  
  // 创建泛型类时自动推断
  var container = Container(value: 'hello');  // Container<String>
}

六、泛型扩展

6.1 泛型扩展方法

extension ReverseList<T> on List<T> {
  List<T> reversedList() {
    return reversed.toList();
  }

  List<T> shuffleList() {
    List<T> result = List.from(this);
    result.shuffle();
    return result;
  }
}

void main() {
  List<int> numbers = [1, 2, 3, 4, 5];
  print('列表反转: ${numbers.reversedList()}');         // 输出: 列表反转: [5, 4, 3, 2, 1]
  print('列表随机打乱: ${numbers.shuffleList()}');  // 输出: 列表随机打乱: [3, 1, 5, 2, 4]

  List<String> names = ['张三', '李四', '王五'];
  print('字符串列表反转: ${names.reversedList()}');  // 输出: 字符串列表反转: [王五, 李四, 张三]
}

6.2 特定类型扩展

extension JoinStrings on List<String> {
  String joinWithSeparator(String separator) {
    return join(separator);
  }
}

extension MapValuesExtension<K, V extends num> on Map<K, V> {
  num sumValues() {
    num sum = 0;
    for (V value in values) {
      sum += value;
    }
    return sum;
  }

  V? maxValue() {
    if (isEmpty) return null;
    V max = values.first;
    for (V value in values) {
      if (value > max) {
        max = value;
      }
    }
    return max;
  }
}

void main() {
  List<String> names = ['张三', '李四', '王五'];
  print('字符串列表拼接: ${names.joinWithSeparator(' | ')}');  // 输出: 字符串列表拼接: 张三 | 李四 | 王五

  Map<String, int> scores = {'张三': 90, '李四': 85, '王五': 95};
  print('Map值求和: ${scores.sumValues()}');   // 输出: Map值求和: 270
  print('Map最大值: ${scores.maxValue()}');   // 输出: Map最大值: 95
}

七、实战:通用数据解析工具

7.1 需求分析

在个人信息卡片应用中,我们需要实现一个通用的数据解析工具,支持:

  1. JSON字符串解析
  2. 从Map中提取指定类型的值
  3. 将JSON数组解析为对象列表
  4. 对象序列化和反序列化

7.2 数据模型定义

class User {
  final String name;
  final int age;

  User({required this.name, required this.age});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      age: json['age'] as int,
    );
  }

  Map<String, dynamic> toJson() {
    return {'name': name, 'age': age};
  }
}

7.3 数据解析工具实现

class DataParser {
  Map<String, dynamic> parseJson(String jsonString) {
    return _parseJsonString(jsonString);
  }

  T extractValue<T>(Map<String, dynamic> map, String key) {
    return map[key] as T;
  }

  List<T> parseList<T>(List<dynamic> list, T Function(Map<String, dynamic>) fromJson) {
    return list.map((item) => fromJson(item as Map<String, dynamic>)).toList();
  }

  String serialize<T>(T object) {
    if (object is User) {
      Map<String, dynamic> json = object.toJson();
      return json.toString();
    }
    return object.toString();
  }

  T deserialize<T>(String data, T Function(Map<String, dynamic>) fromJson) {
    Map<String, dynamic> json = _parseJsonString(data);
    return fromJson(json);
  }

  Map<String, dynamic> _parseJsonString(String jsonString) {
    Map<String, dynamic> result = {};
    String trimmed = jsonString.replaceAll(RegExp(r'\s+'), '');
    String content = trimmed.substring(1, trimmed.length - 1);

    List<String> pairs = content.split(',');
    for (String pair in pairs) {
      List<String> parts = pair.split(':');
      if (parts.length == 2) {
        String key = parts[0].replaceAll('"', '');
        String value = parts[1].replaceAll('"', '');
        if (int.tryParse(value) != null) {
          result[key] = int.parse(value);
        } else {
          result[key] = value;
        }
      }
    }
    return result;
  }
}

7.4 使用示例

void _dataParserExample() {
  DataParser parser = DataParser();

  String jsonString = '''
    {
      "id": "user_001",
      "name": "付文龙",
      "age": 30,
      "email": "372699828@qq.com"
    }
  ''';

  Map<String, dynamic> jsonMap = parser.parseJson(jsonString);
  print('解析JSON: $jsonMap');

  String name = parser.extractValue<String>(jsonMap, 'name');
  int age = parser.extractValue<int>(jsonMap, 'age');
  print('提取姓名: $name');   // 输出: 提取姓名: 付文龙
  print('提取年龄: $age');    // 输出: 提取年龄: 30

  List<Map<String, dynamic>> usersJson = [
    {'name': '张三', 'age': 25},
    {'name': '李四', 'age': 28},
    {'name': '王五', 'age': 32},
  ];

  List<User> users = parser.parseList<User>(usersJson, (json) => User.fromJson(json));
  print('\n解析用户列表:');
  for (User user in users) {
    print('  ${user.name}, ${user.age}岁');
  }

  String serialized = parser.serialize(users[0]);
  print('\n序列化用户: $serialized');

  User deserialized = parser.deserialize<User>(serialized, User.fromJson);
  print('反序列化用户: ${deserialized.name}, ${deserialized.age}岁');
}

7.5 代码解析

泛型方法parseList

  • 使用泛型参数T表示目标类型
  • 接收一个fromJson回调函数,将Map转换为目标类型
  • 返回解析后的对象列表

泛型方法extractValue

  • 从Map中提取指定类型的值
  • 使用类型转换as T确保类型安全

泛型方法serialize/deserialize

  • 支持对象的序列化和反序列化
  • 通过泛型参数指定目标类型

7.6 执行结果

解析JSON: {id: user_001, name: 付文龙, age: 30, email: 372699828@qq.com}
提取姓名: 付文龙
提取年龄: 30

解析用户列表:
  张三, 25岁
  李四, 28岁
  王五, 32岁

序列化用户: {name: 张三, age: 25}
反序列化用户: 张三, 25岁

八、泛型最佳实践

8.1 使用泛型约束提高类型安全

// 不好的做法:没有约束
T process<T>(T value) {
  // 无法调用特定方法
  return value;
}

// 好的做法:使用约束
T process<T extends Shape>(T value) {
  // 可以调用Shape的方法
  value.calculateArea();
  return value;
}

8.2 避免过度泛型化

// 不好的做法:泛型参数过多
class ComplexProcessor<T, U, V, W> {
  // ...
}

// 好的做法:合并相关类型
class Processor<T> {
  void process(List<T> items) {
    // ...
  }
}

8.3 使用typedef简化泛型回调

typedef JsonConverter<T> = T Function(Map<String, dynamic>);

class DataParser {
  List<T> parseList<T>(List<dynamic> list, JsonConverter<T> converter) {
    return list.map((item) => converter(item as Map<String, dynamic>)).toList();
  }
}

8.4 优先使用类型推断

// 显式指定类型(可选)
Container<String> container1 = Container<String>(value: 'hello');

// 类型推断(推荐)
var container2 = Container(value: 'hello');

8.5 为泛型类提供默认类型参数

class Cache<T extends Object?> {
  final Map<String, T> _cache = {};
  
  void put(String key, T value) => _cache[key] = value;
  T? get(String key) => _cache[key];
}

九、在鸿蒙平台的特殊考虑

9.1 平台通道的泛型处理

在鸿蒙平台上,通过MethodChannel传递数据时需要注意类型转换:

static Future<T> invokeMethod<T>(String method, {dynamic arguments}) async {
  const platform = MethodChannel('com.example/harmonyos');
  try {
    final dynamic result = await platform.invokeMethod(method, arguments);
    return result as T;
  } on PlatformException catch (e) {
    throw Exception('调用失败: ${e.message}');
  }
}

9.2 JSON解析的兼容性

确保JSON解析在鸿蒙平台上正常工作:

import 'dart:convert';

Map<String, dynamic> parseJson(String jsonString) {
  return jsonDecode(jsonString) as Map<String, dynamic>;
}

9.3 性能优化

在鸿蒙平台上,注意泛型代码的性能:

  • 避免在循环中创建泛型对象
  • 使用const构造函数减少对象创建
  • 对于频繁调用的泛型函数,考虑使用静态类型优化

十、总结

泛型与类型推断是Dart语言的重要特性,掌握泛型编程能够显著提升代码的复用性和类型安全性。在本文中,我们学习了:

  1. 泛型概述:为什么需要泛型及其优势
  2. 泛型函数:定义和使用泛型函数
  3. 泛型类:创建泛型类和多类型参数
  4. 泛型约束:使用extends约束类型
  5. 类型推断:Dart的自动类型推断机制
  6. 泛型扩展:为集合添加泛型扩展方法
  7. 实战示例:封装通用数据解析工具
  8. 最佳实践:泛型使用的原则和规范
  9. 鸿蒙平台特殊考虑:平台通道和性能优化

通过掌握泛型编程,我们可以编写出更加通用、安全、高效的Flutter代码,为鸿蒙平台上的应用开发提供更好的支持。


附录:完整示例代码

完整的示例代码位于 [010_generics.dart](file:///d:/Flutter/flutter_harmonyos_study/lib/examples/chapter_01/section_1_1/010_generics.dart),包含了所有示例和实战代码。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐