dart学习第 6 节:函数进阶 —— 高阶函数与闭包

今天我们将深入函数的高级特性 ------高阶函数闭包。这些特性是 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
}

counter1counter2 是两个独立的闭包,它们各自的 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 聚合结果,用闭包创建了带状态的折扣计算器,充分体现了高阶函数和闭包的灵活性。

相关推荐
叽哥3 小时前
dart学习第 8 节:面向对象(下)—— 继承与多态
flutter·dart
叽哥6 小时前
dart学习第 13 节:异步编程基础 —— Future 与 async/await
flutter·dart
xiaoyan20157 小时前
基于flutter3.32+window_manager仿macOS/Wins风格桌面os系统
前端·flutter·dart
叽哥7 小时前
dart学习第 11 节: 空安全(下)—— 安全操作符详解
flutter·dart
weixin_4111918417 小时前
原生安卓与flutter混编的实现
android·flutter
会煮咖啡的猫1 天前
编写 Flutter 游戏摇杆组件
flutter
来来走走1 天前
Flutter dart运算符
android·前端·flutter
风清云淡_A1 天前
【Flutter3.8x】flutter从入门到实战基础教程(五):Material Icons图标的使用
前端·flutter
阳光明媚sunny1 天前
Flutter基础知识
flutter