[Flutter]足够入门的Dart语言系列之函数:匿名函数、作用域闭包、类型别名和内联函数类型

简介: 函数在Dart中是对象,因此,可以将函数作为参数传递给另一个函数、作为一个'值'赋值给一个变量。下面主要介绍匿名函数、内联函数类型的使用,以及了解下作用域和闭包...

函数在Dart中是对象,因此,可以将函数作为参数传递给另一个函数、作为一个'值'赋值给一个变量。下面主要介绍匿名函数、内联函数类型的使用,以及了解下作用域和闭包、类型别名...

匿名函数(Anonymous functionlambda表达式)

在创建函数时通常都是有名字的,如果创建一个没有名字的方法,则称之为“匿名函数”,有时也被称为lambda或闭包(Closure)。

可以将匿名函数赋值给一个变量、将其添加到集合或从中删除。

与命名函数的的定义一样,只是没有函数名:

([[Type] param1[, …]]) {
  codeBlock;
};

下面是一个参数为item且没有参数类型的匿名方法,作为参数传递给List的forEach方法:

const list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

如果函数体只有一句,可以使用箭头表示法简写:

list.forEach((item) => print('${list.indexOf(item)}: $item'));

作用域和闭包

Lexical scope 词法作用域、Lexical closure 词法闭包

Dart是有词法作用域的语言,也就是,变量的作用域在写代码的那一刻就确定了,{}大括号定义一个完整的块级作用域,大括号内定义的变量只能在大括号内访问。

块内的变量无法在外部被访问:

内层可以访问外层(任何一级)的变量。

闭包通俗来讲就是访问了函数外部变量的函数,在使用时获取了该函数,同时由于引用了外部变量,也要维持一份包含函数外部变量的环境。

闭包是一个可以访问其词法作用域内的变量的函数对象,即使在它原始作用域之外被调用时。

闭包可以封闭定义在其作用域内的变量。下面的示例,函数 makeAdder() 捕获了变量 addBy,其内的子函数无论何时返回,变量都会被记录保持。

/// 返回一个子函数,可以在其他地方调用,调用时使用子函数所在作用域中的addBy
Function makeAdder(int addBy) {
  return (int i) => addBy + i;
}

void main() {
  // 加2的函数
  var add2 = makeAdder(2);

  // 加6的函数
  var add6 = makeAdder(6);

  print(add2(3) == 5);  // true
  print(add6(3) == 9);  // true
}

也可以是使用了局部变量的闭包。

Function makeAdder2(int addBy) {
  var k=10;
  return (int i) => (addBy + i)*k;
}

typedef 类型别名(类型定义,v2.13开始可用于任何类型)

typedef关键字用于为某一个类型起别名,通过类型别名可以非常方便的引用某一类型,常常也被称为类型定义,类型别名就表示了一种类型。

比如,为List<int>声明一个类型别名IntList,然后就是使用该别名代替原来的类型:

typedef IntList = List<int>;
IntList il = [1, 2, 3];

同时,类型别名也可以用于泛型类型的定义。

在 2.13 版本之前,typedef仅限于函数类型,从v2.13开始可以更广泛的应用于其他对象类型。

使用内联函数类型声明(不推荐typedef

在Dart1中,如果想要将函数类型作为字段、变量或泛型参数使用,必须首先通过typedef为其定义一个类型别名。

比如下面,为double Function(double)类型的函数定义别名Operation

typedef Operation = double Function(double);

然后将改类型的函数作为变量定义,并调用:

main(){
   Operation op = square;

   // 调用
   op(10);      100.0
   op.call(15); 225.0
}

double square(double a)=> a * a;

作为Operation类型的op变量可以在代码中指代任何其他符合double Function(double)签名的函数。

但着却有很大的一个问题,即真实的函数类型不够明确,使用者更希望知道函数使用时的真实类型。

内联函数类型作为变量类型

Dart2引入了内联函数类型(inline function type)。即直接使用函数类型声明而不是typedef别名【推荐做法】

double Function(double) op = square;

// 调用
print(op(10));
print(op.call(15));

赋值给op变量其他的函数实现,比如下面计算三次方:

double Function(double) op = square;

op = cube; 
print(op(10)); // 1000

  
double cube(double a) => a * a * a;

函数类型作为函数的参数

内联函数类型也可用于函数的参数中。

如下,add方法中声明了double Function(double)?类型的可选命名参数opArg,其中 ?表示该类型可为空,不为空时用于操作每个加法元素之后再相加。

// opArg 操作每个加法元素
double add(double a, double b, {double Function(double)? opArg}) {
  if (opArg == null) return a + b;
  return opArg(a) + opArg(b);
}

square作为opArg命名参数传入:

double result = add(8, 6, opArg: square);
print(result); // 100.0

同样的,满足函数类型的匿名函数,也可以作为变量的值或函数的入参参数。

double result2 = add(8, 6, opArg: (double e) => e * e * e);
print(result2); // 728.0

double result3 = add(8, 6, opArg: (e) => e * e * e);
print(result3); // 28.0

函数的封装作用

函数用于将可以完成一定功能的一段代码集成在一起,通过逻辑算法完成某项任务,这就是封装的概念。

函数最大的作用就是对功能的封装,使用者不需要关注其中具体的实现细节,只在需要时进行调用即可,该函数对于使用者来说就是一个实现某个功能的黑盒

在此基础上,还可以引申出类的封装、程序包或程序库的封装,通过使用官方或第三方提供的工具库,我们可以很方便的实现各种功能,如果有能力,还可以完善这些功能的实现细节或过程。

当然,需要注意的是,避免过渡依赖其他库或实现。

参考

相关文章
|
19天前
|
前端开发 C++ 容器
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
|
9天前
|
Dart 安全
简化代码、提高效率:Dart和Flutter开发小技巧
在日常开发中,我们常常会使用一些常用的技巧或语法糖,以简化代码、提高开发效率。本文将分享一些在Dart和Flutter中常用的小贴士,帮助你更轻松地编写优雅高效的代码。
简化代码、提高效率:Dart和Flutter开发小技巧
|
21天前
|
Dart 前端开发 开发者
【Flutter前端技术开发专栏】Flutter Dart语言基础语法解析
【4月更文挑战第30天】Dart是Google为Flutter框架打造的高效编程语言,具有易学性、接口、混入、抽象类等特性。本文概述了Dart的基础语法,包括静态类型(如int、String)、控制流程(条件、循环)、函数、面向对象(类与对象)和异常处理。此外,还介绍了库导入与模块使用,帮助开发者快速入门Flutter开发。通过学习Dart,开发者能创建高性能的应用。
【Flutter前端技术开发专栏】Flutter Dart语言基础语法解析
|
开发工具 Android开发 iOS开发
Flutter从入门到实战
版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u013132758。 https://blog.csdn.net/u013132758/article/details/80474494 Flutter从入门到实战 Flutter概述   Flutter是一款移动应用程序SDK,一份代码可以同时生成iOS和Android两个高性能、高保真的应用程序。
2231 0
|
21天前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
|
21天前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
【4月更文挑战第30天】对比 Flutter(Dart,强类型,Google支持,快速热重载,高性能渲染)与 React Native(JavaScript,庞大生态,热重载,依赖原生渲染),文章讨论了开发语言、生态系统、性能、开发体验、学习曲线、社区支持及项目选择因素。两者各有优势,选择取决于项目需求、团队技能和长期维护考虑。参考文献包括官方文档和性能比较文章。
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
|
19天前
|
Android开发
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
Flutter完整开发实战详解(六、 深入Widget原理),2024百度Android岗面试真题收录解析
|
19天前
|
XML Dart Java
Flutter插件开发之APK自动安装,字节跳动Android岗面试题
Flutter插件开发之APK自动安装,字节跳动Android岗面试题
|
20天前
|
Java Android开发 设计模式
flutter音视频开发,Android开发需要学什么
flutter音视频开发,Android开发需要学什么
|
21天前
|
Dart 前端开发 测试技术
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
【4月更文挑战第30天】随着Flutter在跨平台开发的普及,保证代码质量成为开发者关注的重点。优质代码能确保应用性能与稳定性,提高开发效率。关键策略包括遵循最佳实践,编写可读性强的代码,实施代码审查和自动化测试。重构实践在项目扩展时尤为重要,适时重构能优化结构,降低维护成本。开发者应重视代码质量和重构,以促进项目成功。
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践