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

相关推荐
程序员老刘17 小时前
一杯奶茶钱,PicGo + 阿里云 OSS 搭建永久稳定的个人图床
flutter·markdown
奋斗的小青年!!20 小时前
OpenHarmony Flutter 拖拽排序组件性能优化与跨平台适配指南
flutter·harmonyos·鸿蒙
小雨下雨的雨21 小时前
Flutter 框架跨平台鸿蒙开发 —— Stack 控件之三维层叠艺术
flutter·华为·harmonyos
行者961 天前
OpenHarmony平台Flutter手风琴菜单组件的跨平台适配实践
flutter·harmonyos·鸿蒙
小雨下雨的雨1 天前
Flutter 框架跨平台鸿蒙开发 —— Flex 控件之响应式弹性布局
flutter·ui·华为·harmonyos·鸿蒙系统
cn_mengbei1 天前
Flutter for OpenHarmony 实战:CheckboxListTile 复选框列表项详解
flutter
cn_mengbei1 天前
Flutter for OpenHarmony 实战:Switch 开关按钮详解
flutter
奋斗的小青年!!1 天前
OpenHarmony Flutter实战:打造高性能订单确认流程步骤条
flutter·harmonyos·鸿蒙
Coder_Boy_1 天前
Flutter基础介绍-跨平台移动应用开发框架
spring boot·flutter
cn_mengbei1 天前
Flutter for OpenHarmony 实战:Slider 滑块控件详解
flutter