我们在系列四中已经介绍了Dart中有关Function的基本概念,今天我们来围绕“函数作为一等公民,作为对象”这一概念来展开讨论和总结。
将一个函数赋值给一个变量.
1
2
3
4
5
6
7 1add(int a, int b) => a + b;
2
3void main() {
4 var sum = add;
5 print(sum(1, 2)); // 打印3
6}
7
对于add函数,我们将其赋值给变量sum,然后照样可以通过sum来调用函数,执行两个int整数的求和运算。
将一个函数作为另一个函数的参数,进行传递.
1
2
3
4
5
6
7
8
9
10
11
12
13 1run(operate, a, b) {
2 return operate(a, b);
3}
4
5add(int a, int b) => a + b;
6
7sub(int a, int b) => a - b;
8
9void main() {
10 print(run(add, 1, 2)); // 打印3
11 print(run(sub, 1, 2)); // 打印-1
12}
13
在使用run函数时,我们分别将add函数、sub函数作为它的第一个参数进行传递。
将函数作为另一个函数的返回值.
1
2
3
4
5
6
7
8
9
10
11 1add(int a, int b) => a + b;
2
3sub(int a, int b) => a - b;
4
5void main() {
6 print(select(true)(1, 2)); // 打印3
7 print(select(false)(1, 2)); // 打印-1
8}
9
10select(bool isAdd) => isAdd ? add : sub;
11
直接来看select函数,我们根据isAdd的true或false,来决定是将add函数或sub函数返回
将函数对象存储在数据结构里,比如数组.
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1add(int a, int b) => a + b;
2
3sub(int a, int b) => a - b;
4
5void main() {
6 var operations = [add, sub];
7 operations.forEach((op) {
8 print(op(1, 2));
9 });
10}
11输出结果为:
123
13-1
14
一个有趣的例子,作为闭包概念的引导:
1
2
3
4
5
6
7
8
9
10
11
12 1void main() {
2 int a;
3 second() {
4 a = 12;
5 return a;
6 }
7
8 print(a);
9 print(second());
10 print(a);
11}
12
先不看输出结果,我们来看整个代码结构:
- 我们在main()中定义了一个second(),说明Function是可以嵌套定义的
-
我们在second()中对外部的局部变量a重新赋值,在Java里,局部内部类里是不允许修改外部的局部变量的。而Dart以及Kotlin这种现代语言,这块是允许直接修改的。输出结果:
-
1
2
3
4 1null
212
312
4
-
闭包。闭包并不是Dart中独有的一个概念,在Js和py中都有,并且Dart中的闭包的概念和JS很像。闭包就是能够读取其他函数内部变量的函数。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 1Function makeAdder(num addBy) {
2 return (num i) => addBy + i;
3}
4
5void main() {
6 var add2 = makeAdder(2);
7 var add4 = makeAdder(4);
8
9 print(add2(3));
10 print(add4(3));
11}
12输出结果:
135
147
15
我们来分析这段程序:
- makeAdder函数:接收一个num类型的参数,然后返回了一个匿名Function,这个匿名Function,会接收一个num参数,然后和makeAdder函数的入参进行求和运算。
- var add2 = makeAdder(2): 这里add2它实际上是一个Function类型的对象,就是我们前面提到的那个接收一个num参数的匿名Function。所以我们执行add2(3) 自然会得到结果5(2 + 3)。
在makeAdder函数中的addBy参数,作为一个局部变量,只在当前函数可见,但是你会发现,我们通过闭包,在函数外部访问到了函数内部的变量。
-
我们最后再看一个例子,来加深对闭包的理解:
1
2
3
4
5
6
7
8
9
10
11 1calculate(base) {
2 var count = 1;
3 return () => print('Value is ${base + count++}');
4}
5
6void main(){
7 var f = calculate(2);
8 f();
9 f();
10}
11
这里的输出结果又是什么呢?
1
2
3 1Value is 3
2Value is 4
3
实际上我们可以这样去看待:
一旦形成闭包,闭包函数中对于外部变量的引用,最终会导致闭包函数内,也就是这个Function对象会有一个与之对应的成员变量。结合上面的例子来看,也就是f对象中有两个成员变量:base、count,由于base的值保持不变,count在每次调用中都会自增,那么自然而然会有这样的输出结果。