今天我们将深入函数的高级特性 ------高阶函数 与闭包。这些特性是 Dart 函数式编程的核心,能让代码更简洁、更灵活,也是 Flutter 开发中的常用技巧。
一、高阶函数:以函数为 "数据" 的函数
高阶函数是指可以接收函数作为参数,或返回一个函数作为结果的函数。简单说,就是能 "操作" 其他函数的函数。
1. 函数作为参数
当函数作为参数传递时,我们可以将通用逻辑抽象出来,让函数更具扩展性。
示例:通用计算框架
dart
// 高阶函数:接收两个数字和一个运算函数
void calculate(int a, int b, int Function(int, int) operation) {
int result = operation(a, b);
print("计算结果:$result");
}
// 定义具体的运算函数
int add(int x, int y) => x + y;
int multiply(int x, int y) => x * y;
void main() {
// 传递加法函数
calculate(3, 4, add); // 输出:计算结果:7
// 传递乘法函数(也可以直接传匿名函数)
calculate(3, 4, multiply); // 输出:计算结果:12
calculate(3, 4, (x, y) => x - y); // 输出:计算结果:-1
}
这个例子中,calculate
就是高阶函数,它不关心具体的运算逻辑,只负责执行传入的 operation
函数。这种模式在框架设计中非常常见。
2. 函数作为返回值
函数作为返回值时,我们可以动态生成具有特定行为的函数。
示例:生成自定义计算器
dart
// 高阶函数:根据操作符返回对应的运算函数
Function getCalculator(String operator) {
switch (operator) {
case "+":
return (int a, int b) => a + b;
case "-":
return (int a, int b) => a - b;
case "*":
return (int a, int b) => a * b;
case "/":
return (int a, int b) => a ~/ b; // 整数除法
default:
return (int a, int b) => 0;
}
}
void main() {
// 获取加法计算器
var adder = getCalculator("+");
print(adder(5, 3)); // 输出:8
// 获取乘法计算器
var multiplier = getCalculator("*");
print(multiplier(5, 3)); // 输出:15
}
这里的 getCalculator
根据输入的运算符,动态返回不同的运算函数,实现了 "按需生成" 函数的效果。
二、常用高阶函数:forEach/map/reduce
Dart 的集合类(List、Set 等)内置了许多实用的高阶函数,让数据处理变得异常简洁。
1. forEach:遍历集合
forEach
接收一个函数作为参数,用于遍历集合中的每个元素(我们在上一节课接触过)。
dart
void main() {
List<String> languages = ['Dart', 'Flutter', 'Java'];
// 遍历并打印每个元素
languages.forEach((lang) {
print("语言:$lang");
});
// 输出:
// 语言:Dart
// 语言:Flutter
// 语言:Java
}
2. map:转换集合元素
map
接收一个转换函数,将集合中的每个元素按规则转换,返回一个新的可迭代对象(通常用 toList()
转为列表)。
示例:数据转换
dart
void main() {
List<int> numbers = [1, 2, 3, 4];
// 将每个数字转换为其平方
var squared = numbers.map((n) => n * n);
print(squared.toList()); // 输出:[1, 4, 9, 16]
// 将整数列表转换为字符串列表
var numberStrings = numbers.map((n) => "数字:$n");
print(numberStrings.toList()); // 输出:[数字:1, 数字:2, 数字:3, 数字:4]
}
3. reduce:聚合集合元素
reduce
接收一个聚合函数,将集合中的元素逐个合并为一个结果(从第一个元素开始,逐步与下一个元素运算)。
示例:求和与求积
dart
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
// 求和:((((1+2)+3)+4)+5) = 15
int sum = numbers.reduce((value, element) => value + element);
print("总和:$sum"); // 输出:总和:15
// 求积:((((1*2)*3)*4)*5) = 120
int product = numbers.reduce((value, element) => value * element);
print("乘积:$product"); // 输出:乘积:120
}
4. 链式调用:组合高阶函数
这些高阶函数可以链式调用,实现复杂的数据处理逻辑:
dart
void main() {
List<int> scores = [85, 92, 78, 65, 90];
// 步骤1:筛选出大于80的分数
// 步骤2:将分数转换为"优秀:XX"的字符串
// 步骤3:遍历打印结果
scores
.where((s) => s > 80) // 筛选:[85, 92, 90]
.map((s) => "优秀:$s") // 转换:["优秀:85", "优秀:92", "优秀:90"]
.forEach((s) => print(s)); // 遍历打印
// 输出:
// 优秀:85
// 优秀:92
// 优秀:90
}
这种链式调用的风格非常简洁,避免了冗长的循环和临时变量。
三、闭包:函数与变量的 "绑定"
闭包是指在嵌套函数中,内部函数引用了外部函数的变量,并且内部函数被返回或传递到外部时形成的结构。简单说,就是函数 "记住" 了它创建时所处的环境。
1. 闭包的基本形式
dart
// 外部函数
Function makeCounter() {
int count = 0; // 外部函数的局部变量
// 内部函数(闭包):引用了外部的count变量
int increment() {
count++;
return count;
}
return increment; // 返回内部函数
}
void main() {
// 获取闭包函数
var counter = makeCounter();
// 多次调用,发现count被"记住"了
print(counter()); // 输出:1
print(counter()); // 输出:2
print(counter()); // 输出:3
}
这个例子中,increment
函数就是闭包。它引用了外部函数 makeCounter
中的 count
变量,即使 makeCounter
执行完毕,count
也不会被销毁,而是被 increment
函数 "保存" 了下来。
2. 闭包的核心特性:变量隔离
每个闭包都会独立保存自己的变量环境,互不干扰:
dart
Function makeCounter() {
int count = 0;
return () {
count++;
return count;
};
}
void main() {
var counter1 = makeCounter();
var counter2 = makeCounter();
print(counter1()); // 1(counter1的count)
print(counter1()); // 2
print(counter2()); // 1(counter2的count,与counter1无关)
print(counter2()); // 2
}
counter1
和 counter2
是两个独立的闭包,它们各自的 count
变量互不影响,实现了变量的隔离。
3. 闭包的实际应用场景
- 封装私有变量 :Dart 没有
private
关键字,但可以用闭包模拟私有变量。 - 缓存计算结果:存储 expensive 计算的结果,避免重复计算。
- 事件处理:在回调函数中保留上下文信息。
示例:模拟私有变量
dart
class User {
// 用闭包实现"私有"的密码变量
final _password = (() {
String _secret = "123456"; // 外部无法直接访问
return {'get': () => _secret, 'set': (String newPwd) => _secret = newPwd};
})();
String name;
User(this.name);
// 只能通过方法访问"私有"密码
String getPassword() => _password['get']!();
void setPassword(String newPwd) => _password['set']!(newPwd);
}
void main() {
User user = User("张三");
print(user.getPassword()); // 输出:123456
user.setPassword("abcdef");
print(user.getPassword()); // 输出:abcdef
// 无法直接访问_secret(编译错误)
// print(user._secret);
}
四、高阶函数与闭包的综合案例
我们用一个 "购物车计算" 案例,综合运用本节课的知识:
dart
void main() {
// 购物车商品列表:[名称, 单价, 数量]
List<List<dynamic>> cart = [
['苹果', 5.99, 2],
['香蕉', 3.99, 3],
['橙子', 4.50, 1],
];
// 1. 计算每个商品的总价(单价*数量)- 使用map
var itemTotals = cart.map((item) => item[1] * item[2]);
// 2. 计算购物车总价 - 使用reduce
double total = itemTotals.reduce((sum, price) => sum + price);
// 3. 创建一个带折扣的价格计算器(闭包)
Function createDiscountCalculator(double discount) {
return (double price) => price * (1 - discount);
}
// 4. 使用9折计算器计算最终价格
var discount90 = createDiscountCalculator(0.1);
double finalTotal = discount90(total);
print("原价:${total.toStringAsFixed(2)}元"); // 输出:原价:28.45元
print("9折后:${finalTotal.toStringAsFixed(2)}元"); // 输出:9折后:25.61元
}
这个案例中,我们用 map
转换数据,用 reduce
聚合结果,用闭包创建了带状态的折扣计算器,充分体现了高阶函数和闭包的灵活性。