泛型与类型推断:Flutter在鸿蒙平台封装通用数据解析工具



作者:付文龙(红目香薰)
仓库地址: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 需求分析
在个人信息卡片应用中,我们需要实现一个通用的数据解析工具,支持:
- JSON字符串解析
- 从Map中提取指定类型的值
- 将JSON数组解析为对象列表
- 对象序列化和反序列化
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语言的重要特性,掌握泛型编程能够显著提升代码的复用性和类型安全性。在本文中,我们学习了:
- 泛型概述:为什么需要泛型及其优势
- 泛型函数:定义和使用泛型函数
- 泛型类:创建泛型类和多类型参数
- 泛型约束:使用extends约束类型
- 类型推断:Dart的自动类型推断机制
- 泛型扩展:为集合添加泛型扩展方法
- 实战示例:封装通用数据解析工具
- 最佳实践:泛型使用的原则和规范
- 鸿蒙平台特殊考虑:平台通道和性能优化
通过掌握泛型编程,我们可以编写出更加通用、安全、高效的Flutter代码,为鸿蒙平台上的应用开发提供更好的支持。
附录:完整示例代码
完整的示例代码位于 [010_generics.dart](file:///d:/Flutter/flutter_harmonyos_study/lib/examples/chapter_01/section_1_1/010_generics.dart),包含了所有示例和实战代码。
更多推荐




所有评论(0)