Dart typedef 与函数类型
typedef 是 Dart 中的类型别名机制,它让你为复杂的类型定义简短易读的名称。
本章介绍 typedef 的两种用法:传统的函数类型别名,以及 Dart 3.0 引入的通用类型别名。
typedef 函数类型别名
当一个函数类型被频繁使用时,typedef 可以给它一个清晰的名字。
这对于回调函数、事件处理器等场景特别有用。
实例
// 定义一个函数类型别名
// 表示:接收两个 int 参数,返回 int 的函数
typedef IntOperation = int Function(int a, int b);
// 定义一个回调类型
// 表示:接收 String 消息,无返回值的函数
typedef MessageCallback = void Function(String message);
// 使用 typedef 作为参数类型
int performOperation(int x, int y, IntOperation operation) {
return operation(x, y);
}
void logMessage(String msg, MessageCallback callback) {
print('准备输出消息...');
callback('[RUNOOB] $msg');
}
void main() {
// 传入符合 IntOperation 签名的函数
int add(int a, int b) => a + b;
int multiply(int a, int b) => a * b;
print('10 + 5 = ${performOperation(10, 5, add)}');
print('10 × 5 = ${performOperation(10, 5, multiply)}');
// 也可以直接传入匿名函数
int result = performOperation(20, 4, (a, b) => a ~/ b);
print('20 ÷ 4 = $result');
// 使用 MessageCallback
logMessage('操作完成', (msg) {
print('收到消息: $msg');
});
}
// 表示:接收两个 int 参数,返回 int 的函数
typedef IntOperation = int Function(int a, int b);
// 定义一个回调类型
// 表示:接收 String 消息,无返回值的函数
typedef MessageCallback = void Function(String message);
// 使用 typedef 作为参数类型
int performOperation(int x, int y, IntOperation operation) {
return operation(x, y);
}
void logMessage(String msg, MessageCallback callback) {
print('准备输出消息...');
callback('[RUNOOB] $msg');
}
void main() {
// 传入符合 IntOperation 签名的函数
int add(int a, int b) => a + b;
int multiply(int a, int b) => a * b;
print('10 + 5 = ${performOperation(10, 5, add)}');
print('10 × 5 = ${performOperation(10, 5, multiply)}');
// 也可以直接传入匿名函数
int result = performOperation(20, 4, (a, b) => a ~/ b);
print('20 ÷ 4 = $result');
// 使用 MessageCallback
logMessage('操作完成', (msg) {
print('收到消息: $msg');
});
}
10 + 5 = 15 10 × 5 = 50 20 ÷ 4 = 5 准备输出消息... 收到消息: [RUNOOB] 操作完成
没有 typedef 时,你需要在每个参数位置重复书写冗长的函数类型签名。
有了 typedef,类型声明变得清晰、统一,修改时也只需要改一处。
typedef 只是给类型起了一个别名,它不会创建新的类型。IntOperation 和 int Function(int, int) 在类型系统中完全等价。
函数类型作为参数
在 Dart 中,函数是一等公民(First-class Citizen),可以像普通值一样传递。
实例
// 直接使用函数类型声明参数(不使用 typedef)
void processNumbers(
List<int> numbers,
bool Function(int) filter,
String Function(int) formatter,
) {
var filtered = numbers.where(filter);
for (var n in filtered) {
print(formatter(n));
}
}
// 返回一个函数的高阶函数
int Function(int) makeMultiplier(int factor) {
// 返回的闭包捕获了 factor
return (int n) => n * factor;
}
void main() {
var scores = [55, 78, 92, 60, 45, 88];
print('--- 及格分数 ---');
processNumbers(
scores,
(n) => n >= 60, // 过滤条件
(n) => 'RUNOOB 分数: $n 分', // 格式化
);
print('--- 高分(> 80)---');
processNumbers(
scores,
(n) => n > 80,
(n) => '高分: $n 分',
);
// 函数作为返回值
var doubler = makeMultiplier(2);
var tripler = makeMultiplier(3);
print('5 × 2 = ${doubler(5)}');
print('5 × 3 = ${tripler(5)}');
}
void processNumbers(
List<int> numbers,
bool Function(int) filter,
String Function(int) formatter,
) {
var filtered = numbers.where(filter);
for (var n in filtered) {
print(formatter(n));
}
}
// 返回一个函数的高阶函数
int Function(int) makeMultiplier(int factor) {
// 返回的闭包捕获了 factor
return (int n) => n * factor;
}
void main() {
var scores = [55, 78, 92, 60, 45, 88];
print('--- 及格分数 ---');
processNumbers(
scores,
(n) => n >= 60, // 过滤条件
(n) => 'RUNOOB 分数: $n 分', // 格式化
);
print('--- 高分(> 80)---');
processNumbers(
scores,
(n) => n > 80,
(n) => '高分: $n 分',
);
// 函数作为返回值
var doubler = makeMultiplier(2);
var tripler = makeMultiplier(3);
print('5 × 2 = ${doubler(5)}');
print('5 × 3 = ${tripler(5)}');
}
--- 及格分数 --- RUNOOB 分数: 78 分 RUNOOB 分数: 92 分 RUNOOB 分数: 60 分 RUNOOB 分数: 88 分 --- 高分(> 80)--- 高分: 92 分 高分: 88 分 5 × 2 = 10 5 × 3 = 15
回调模式
回调模式是函数类型最常见的应用场景。
它将"做什么"的控制权交给调用者,让代码更灵活和可复用。
实例
// 定义回调类型
typedef ResultCallback<T> = void Function(T result);
typedef ErrorCallback = void Function(String error);
// 模拟异步操作
void fetchUserData(
String userId, {
required ResultCallback<Map<String, dynamic>> onSuccess,
required ErrorCallback onError,
}) {
// 模拟网络请求
print('正在获取用户数据...');
// 模拟成功/失败
if (userId == 'runoob') {
var data = {
'id': 'runoob',
'name': 'RUNOOB 用户',
'level': 'VIP',
};
onSuccess(data);
} else {
onError('用户 $userId 不存在');
}
}
void main() {
// 使用回调处理结果
fetchUserData(
'runoob',
onSuccess: (data) {
print('获取成功!');
print('用户名: ${data['name']}');
print('等级: ${data['level']}');
},
onError: (error) {
print('获取失败: $error');
},
);
print('---');
// 测试失败情况
fetchUserData(
'unknown',
onSuccess: (data) {
print('获取成功');
},
onError: (error) {
print('获取失败: $error');
},
);
}
typedef ResultCallback<T> = void Function(T result);
typedef ErrorCallback = void Function(String error);
// 模拟异步操作
void fetchUserData(
String userId, {
required ResultCallback<Map<String, dynamic>> onSuccess,
required ErrorCallback onError,
}) {
// 模拟网络请求
print('正在获取用户数据...');
// 模拟成功/失败
if (userId == 'runoob') {
var data = {
'id': 'runoob',
'name': 'RUNOOB 用户',
'level': 'VIP',
};
onSuccess(data);
} else {
onError('用户 $userId 不存在');
}
}
void main() {
// 使用回调处理结果
fetchUserData(
'runoob',
onSuccess: (data) {
print('获取成功!');
print('用户名: ${data['name']}');
print('等级: ${data['level']}');
},
onError: (error) {
print('获取失败: $error');
},
);
print('---');
// 测试失败情况
fetchUserData(
'unknown',
onSuccess: (data) {
print('获取成功');
},
onError: (error) {
print('获取失败: $error');
},
);
}
正在获取用户数据... 获取成功! 用户名: RUNOOB 用户 等级: VIP --- 正在获取用户数据... 获取失败: 用户 unknown 不存在
回调模式的常见应用场景:
| 场景 | 回调类型示例 |
|---|---|
| 网络请求 | onSuccess(data) / onError(error) |
| UI 事件 | onTap() / onLongPress() |
| 数据转换 | map()、where()、reduce() 中的回调 |
| 定时器 | Timer(callback, duration) |
| 动画完成 | onComplete() |
虽然回调模式很灵活,但在处理多层异步操作时会导致"回调地狱"。Dart 提供了 async/await 来更优雅地处理异步流程,我们将在第 17 章详细介绍。
Dart 3.0 通用类型别名
Dart 3.0 扩展了 typedef 的能力,现在你可以为任何类型创建别名,不仅仅是函数类型。
实例
// Dart 3.0:typedef 可以为任何类型创建别名
// 复杂集合类型的别名
typedef JsonMap = Map<String, dynamic>;
typedef UserList = List<Map<String, dynamic>>;
// 泛型别名
typedef Result<T> = ({T data, String? error});
// 函数类型别名(传统用法)
typedef Validator<T> = String? Function(T value);
// 使用类型别名
void processJson(JsonMap json) {
print('处理 JSON: $json');
print('键的数量: ${json.length}');
}
void validateAndPrint<T>(T value, Validator<T> validator) {
var error = validator(value);
if (error != null) {
print('验证失败: $error');
} else {
print('验证通过: $value');
}
}
void main() {
// 使用 JsonMap 别名
JsonMap userData = {
'name': 'runoob',
'age': 10,
'isVip': true,
};
processJson(userData);
// 使用 Result 别名
Result<String> successResult = (data: '操作成功', error: null);
Result<String> errorResult = (data: '', error: '网络连接超时');
print('成功: ${successResult.data}');
print('失败: ${errorResult.error}');
// 使用泛型 Validator
Validator<String> nameValidator = (value) {
if (value.isEmpty) return '名称不能为空';
if (value.length < 3) return '名称至少 3 个字符';
return null; // null 表示验证通过
};
validateAndPrint('RUNOOB', nameValidator);
validateAndPrint('AB', nameValidator);
}
// 复杂集合类型的别名
typedef JsonMap = Map<String, dynamic>;
typedef UserList = List<Map<String, dynamic>>;
// 泛型别名
typedef Result<T> = ({T data, String? error});
// 函数类型别名(传统用法)
typedef Validator<T> = String? Function(T value);
// 使用类型别名
void processJson(JsonMap json) {
print('处理 JSON: $json');
print('键的数量: ${json.length}');
}
void validateAndPrint<T>(T value, Validator<T> validator) {
var error = validator(value);
if (error != null) {
print('验证失败: $error');
} else {
print('验证通过: $value');
}
}
void main() {
// 使用 JsonMap 别名
JsonMap userData = {
'name': 'runoob',
'age': 10,
'isVip': true,
};
processJson(userData);
// 使用 Result 别名
Result<String> successResult = (data: '操作成功', error: null);
Result<String> errorResult = (data: '', error: '网络连接超时');
print('成功: ${successResult.data}');
print('失败: ${errorResult.error}');
// 使用泛型 Validator
Validator<String> nameValidator = (value) {
if (value.isEmpty) return '名称不能为空';
if (value.length < 3) return '名称至少 3 个字符';
return null; // null 表示验证通过
};
validateAndPrint('RUNOOB', nameValidator);
validateAndPrint('AB', nameValidator);
}
处理 JSON: {name: runoob, age: 10, isVip: true}
键的数量: 3
成功: 操作成功
失败: 网络连接超时
验证通过: RUNOOB
验证失败: 名称至少 3 个字符
Dart 3.0 的类型别名大大减少了冗长的类型声明,让代码更简洁、更具可读性。
类型别名(typedef)和类型本身在运行时完全等价,它们只是编译期的"昵称"。这意味着你不能用 typedef 来区分两个结构相同但语义不同的类型——它们会被视为同一类型。
