[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

函数的封装作用

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

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

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

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

参考

相关文章
|
8天前
|
Dart
如何在 Flutter 项目中使用 Dart 语言?
如何在 Flutter 项目中使用 Dart 语言?
108 58
|
4天前
|
开发框架 移动开发 Android开发
安卓与iOS开发中的跨平台解决方案:Flutter入门
【9月更文挑战第30天】在移动应用开发的广阔舞台上,安卓和iOS两大操作系统各自占据半壁江山。开发者们常常面临着选择:是专注于单一平台深耕细作,还是寻找一种能够横跨两大系统的开发方案?Flutter,作为一种新兴的跨平台UI工具包,正以其现代、响应式的特点赢得开发者的青睐。本文将带你一探究竟,从Flutter的基础概念到实战应用,深入浅出地介绍这一技术的魅力所在。
21 7
|
2月前
|
Dart JavaScript 前端开发
Dart或Flutter中解决异常-type ‘int‘ is not a subtype of type ‘double‘
Dart或Flutter中解决异常-type ‘int‘ is not a subtype of type ‘double‘
77 4
|
2月前
|
Kubernetes Cloud Native 搜索推荐
探索云原生技术:Kubernetes入门与实践打造个性化安卓应用:从零开始的Flutter之旅
【8月更文挑战第31天】云原生技术正改变着应用开发和部署的方式。本文将带你了解云原生的基石——Kubernetes,通过实际的代码示例,从安装到部署一个简单的应用,让你迅速掌握Kubernetes的核心概念和操作方法。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你进入云原生世界的桥梁。
|
2月前
|
Dart 开发工具
消除Flutter doctor的警告Warning: `dart` on your path resolves to xxx/bin/dart
消除Flutter doctor的警告Warning: `dart` on your path resolves to xxx/bin/dart
32 0
|
Dart
Flutter之基本数据类型测试
Flutter之基本数据类型测试
143 0
|
4月前
|
开发框架 前端开发 测试技术
Flutter开发常见问题解答
Flutter开发常见问题解答
|
5月前
|
前端开发 C++ 容器
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
Flutter-完整开发实战详解(一、Dart-语言和-Flutter-基础)(1)
|
22天前
|
JSON Dart Java
flutter开发多端平台应用的探索
flutter开发多端平台应用的探索
27 6
|
22天前
|
JSON Dart Java
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)
flutter开发多端平台应用的探索 下 (跨模块、跨语言通信之平台通道)
下一篇
无影云桌面