在Dart中,函数被视为一等公民
,这意味着函数可以像普通的变量一样进行传递、赋值和操作
。(如果本文全部忘记,你都要记住这句话)
一、函数 function
1. 函数的基本概念
函数是一段可重复使用的代码块,用于执行特定的任务。它接收输入参数(可选),并返回一个输出结果(可选)。
2. Dart函数的特性
-
一等公民
:在 Dart 中,函数是一等公民,这意味着函数可以像其他数据类型一样被赋值给变量,可以作为参数传递给其他函数,也可以作为函数的返回值。
-
匿名函数
:Dart 支持匿名函数,也称为 lambda 函数或闭包。匿名函数是没有名称的函数,可以用作参数传递给其他函数或直接执行。
-
函数类型
:Dart 具有函数类型,可以声明函数类型的变量。函数类型可以用于指定函数的签名,包括参数类型和返回类型。
-
可选参数和命名参数
:Dart 函数支持可选参数和命名参数。可选参数可以是位置参数或命名参数,位置参数可以通过位置进行传递,而命名参数可以通过名称进行传递。
-
默认参数值
:Dart 函数支持默认参数值,可以在函数定义时为参数指定默认值。如果调用函数时没有提供该参数的值,将使用默认值。
-
闭包
:Dart 支持闭包,闭包是一个函数对象,它可以访问其作用域之外的变量。这意味着即使在其作用域之外调用闭包,它仍然可以访问和修改其创建时所在的作用域中的变量。
-
高阶函数
:Dart 支持高阶函数,即可以接受一个或多个函数作为参数,并且/或者返回一个函数作为结果。这种能力使得编写更具有抽象和灵活性的代码成为可能。
-
函数式编程
:虽然 Dart 是一种面向对象的语言,但它也具有许多函数式编程的特性,如纯函数、不可变数据和不可变状态的推崇,以及对列表、迭代器和延迟计算的支持。
emm,这东西,想写还是写很多的。
挑选几个说说吧。
看起来多,但是谁整天写代码想着这个玩意有多少特性啊。
2.1. 匿名函数
匿名函数,也被称为lambda函数或闭包,是在需要的地方定义和使用的函数,它没有名称。匿名函数在Dart中具有以下特点和应用场景:
- 简洁性和灵活性:匿名函数的语法简洁,可以在需要的地方即时定义和使用,无需为其命名,从而减少了代码的冗余。
- 传递函数作为参数:匿名函数可以作为其他函数的参数传递,从而实现更灵活的函数调用方式。
- 捕获外部变量:匿名函数可以捕获和访问其定义范围之外的变量,即使在其定义之后使用,仍然可以引用和操作外部变量的值。
下面是一些匿名函数的示例,以展示它们的应用场景:
void main() {
// 作为函数参数传递
performOperation((a, b) {
print(a + b);
});
// 与forEach方法结合使用
List<int> numbers = [1, 2, 3, 4, 5];
numbers.forEach((number) {
print(number * 2);
});
// 捕获外部变量
var multiplier = 2;
var doubler = (int number) => number * multiplier;
print(doubler(5)); // 输出: 10
}
在上述示例中,第一个匿名函数作为参数传递给 performOperation
函数,第二个匿名函数与 forEach
方法结合使用来遍历列表,并且第三个匿名函数捕获了外部变量 multiplier
并进行乘法运算。
2.2. 高阶函数
高阶函数是指能够接收一个或多个函数作为参数,并/或返回一个函数的函数。在Dart中,高阶函数的存在为函数式编程提供了强大的支持,具有以下特点和应用场景:
- 函数作为参数传递:高阶函数可以接收其他函数作为参数,使得函数的行为可以通过参数灵活地定制和改变。
- 函数作为返回值:高阶函数可以返回一个新的函数,从而实现函数的动态生成和延迟执行。
下面是一些高阶函数的示例,以展示它们的应用场景:
void main() {
// 函数作为参数
int performOperation(int a, int b, int Function(int, int) operation) {
return operation(a, b);
}
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
print(performOperation(3, 4, add)); // 输出: 7
print(performOperation(3, 4, multiply)); // 输出: 12
// 函数作为返回值
Function calculator(String operation) {
if (operation == 'add') {
return (int a, int b) => a + b;
} else if (operation == 'multiply') {
return (int a, int b) => a * b;
}
return null;
}
var addFunction = calculator('add');
print(addFunction(3, 5)); // 输出: 8
}
在上述示例中,performOperation
函数接收一个函数参数 operation
,并将其应用于传入的两个整数参数。通过将不同的函数(add
和 multiply
)作为参数传递给 performOperation
,可以实现对不同操作的灵活调用。另外,calculator
函数根据不同的操作符返回不同的函数,实现了函数作为返回值的高阶函数。
再来高阶函数的例子
1. 将函数作为参数传递给高阶函数:
// 打印消息的函数
void printMessage(String message) {
print(message);
}
// 高阶函数,接受一个函数作为参数并调用它
void higherOrderFunction(void Function(String) callback) {
callback('你好,世界!');
}
void main() {
higherOrderFunction(printMessage); // 将printMessage函数作为参数传递
}
2. 返回函数的高阶函数:
// 返回一个函数,该函数将传入的参数与x相加
Function adder(int x) {
return (int y) => x + y;
}
void main() {
var addTwo = adder(2); // 返回一个将传入的参数与2相加的函数
print(addTwo(3)); // 输出:5,将3作为参数传递给addTwo函数
}
3. 使用高阶函数实现函数的组合:
// 将传入的参数加1
int addOne(int x) {
return x + 1;
}
// 将传入的参数乘以2
int multiplyTwo(int x) {
return x * 2;
}
// 高阶函数,将传入的函数列表按顺序应用于初始值x,并返回最终结果
int compose(int x, List<Function> functions) {
var result = x;
for (var function in functions) {
result = function(result);
}
return result;
}
void main() {
var composedFunction = compose(5, [addOne, multiplyTwo]); // 将addOne和multiplyTwo函数作为参数传递
print(composedFunction); // 输出:12,先将5传递给addOne函数,然后将结果传递给multiplyTwo函数
}
2.3. 闭包
闭包是指一个函数对象,它可以访问和操作其定义范围之外的变量,即使在其定义之后使用,这种能力被称为"捕获"外部变量。在Dart中,闭包具有以下特点和应用场景:
- 访问外部变量:闭包可以捕获和访问其定义范围之外的变量,即使在其定义之后使用,仍然可以引用和操作外部变量的值。
- 保留状态:闭包可以在函数执行完毕后保留其内部变量的状态,从而实现状态的持久化。
下面是一些闭包的示例,以展示它们的应用场景:
void main() {
// 捕获外部变量
Function createMultiplier(int multiplier) {
return (int number) => number * multiplier;
}
var doubler = createMultiplier(2);
print(doubler(5)); // 输出: 10
// 保留状态
Function counter() {
int count = 0;
return () {
count++;
print(count);
};
}
var increment = counter();
increment(); // 输出: 1
increment(); // 输出: 2
}
在上述示例中,createMultiplier
函数返回一个闭包函数,闭包函数捕获了外部变量 multiplier
并将其与传入的参数相乘。通过调用 createMultiplier
并传递参数,我们创建了一个 doubler
函数,实现了对传入参数的倍增操作。另外,counter
函数返回一个闭包函数,闭包函数保留了内部变量 count
的状态,并在每次调用时进行自增,实现了计数器的功能。
2.4. 函数作为参数和返回值
函数可以作为另一个函数的参数传递,也可以作为另一个函数的返回值返回,这种能力为函数式编程和异步编程提供了强大的支持。
void main() {
// 函数作为参数和返回值的示例
int performOperation(int a, int b, int Function(int, int) operation) {
return operation(a, b);
}
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
print(performOperation(3, 4, add)); // 输出: 7
print(performOperation(3, 4, multiply)); // 输出: 12
}
在上面的例子中,我们定义了一个 performOperation
函数,它接收两个整数参数和一个函数参数 operation
,并调用该函数执行相应的操作。通过将不同的函数作为参数传递给 performOperation
,我们实现了对不同操作的灵活调用。
3. 函数的分类
根据函数的定义位置和使用方式,Dart中的函数可以分为不同的类型。
3.1. 命名函数
命名函数是在Dart中以具有名称的方式定义的函数,可以在任何地方调用。
// 命名函数示例
void sayHello() {
print('Hello!');
}
void main() {
sayHello(); // 输出: Hello!
}
在上面的例子中,我们定义了一个命名函数 sayHello
,它没有参数,当被调用时,会打印出 ‘Hello!’。
3.2. 匿名函数
匿名函数是没有名称的函数,也称为lambda函数或闭包,可以在需要的地方定义和使用。
// 匿名函数示例
void main() {
var add = (int a, int b) {
return a + b;
};
print(add(3, 5)); // 输出: 8
}
在上面的例子中,我们定义了一个匿名函数,并将其赋值给变量 add
。这个匿名函数接收两个整数参数,并返回它们的和。通过变量 add
进行调用,实现了对匿名函数的调用。
3.3. 顶级函数
顶级函数是在Dart文件的顶部定义的函数,可以在整个文件中直接调用。
// 顶级函数示例
void sayHello() {
print('Hello!');
}
void main() {
sayHello(); // 输出: Hello!
}
在上面的例子中,我们在文件的顶部定义了一个顶级函数 sayHello
。该函数没有参数,当被调用时,会打印出 ‘Hello!’。
3.4. 实例方法
实例方法是属于类的函数,必须通过类的实例来调用。
// 实例方法示例
class Calculator {
int add(int a, int b) {
return a + b;
}
}
void main() {
var calculator = Calculator();
print(calculator.add(3, 5)); // 输出: 8
}
在上面的例子中,我们定义了一个 Calculator
类,其中包含一个 add
方法。通过创建 Calculator
的实例 calculator
,我们可以调用实例方法 add
并传递参数,实现了对实例方法的调用。
3.5. 静态方法
静态方法是属于类本身的函数,可以直接通过类名调用,而无需创建类的实例。
// 静态方法示例
class Calculator {
static int add(int a, int b) {
return a + b;
}
}
void main() {
print(Calculator.add(3, 5)); // 输出: 8
}
在上面的例子中,我们定义了一个 Calculator
类,其中包含一个静态方法 add
。通过类名 Calculator
直接调用静态方法 add
,实现了对静态方法的调用。
4. Dart函数的使用
4.1. 函数定义与调用
在Dart中定义函数需要指定函数名称、参数列表和函数体,并通过函数名称进行调用。
// 函数定义与调用示例
int add(int a, int b) {
return a + b;
}
void main() {
print(add(3, 5)); // 输出: 8
}
在上面的例子中,我们定义了一个名为 add
的函数,它接收两个整数参数 a
和 b
,并返回它们的和。在 main
函数中,通过 print
函数调用了 add
函数并传递参数,实现了函数的调用和结果输出。
4.2. 参数与返回值
Dart函数可以接收不同类型和数量的参数,并且可以定义返回值类型或使用推断类型。
// 参数与返回值示例
String greet(String name) {
return 'Hello, $name!';
}
void main() {
print(greet('Alice')); // 输出: Hello, Alice!
}
在上面的例子中,我们定义了一个名为 greet
的函数,它接收一个字符串参数 name
,并返回一个拼接了问候语的字符串。在 main
函数中,通过 print
函数调用了 greet
函数并传递参数,实现了函数的调用和结果输出。
4.3. 可选参数和命名参数
Dart支持可选参数和命名参数,使函数调用更加灵活和可读性更高。
// 可选参数和命名参数示例
void printMessage(String message, {int times = 1}) {
for (int i = 0; i < times; i++) {
print(message);
}
}
void main() {
printMessage('Hello'); // 输出: Hello
printMessage('Hi', times: 3); // 输出: Hi Hi Hi
}
在上面的例子中,我们定义了一个名为 printMessage
的函数,它接收一个字符串参数 message
和一个可选命名参数 times
(默认值为 1)。在函数体中,我们使用了循环打印出指定次数的消息。在 main
函数中,我们通过 printMessage
函数进行了两次调用,一次只传递了必需参数,另一次传递了命名参数,实现了不同参数形式的调用。
4.4. 函数作为参数和返回值的应用
函数作为参数和返回值的特性使得Dart可以支持函数式编程和异步编程的模式。
// 函数作为参数和返回值的示例
void performOperation(void Function() operation) {
operation();
}
void sayHello() {
print('Hello!');
}
void main() {
performOperation(sayHello); // 输出: Hello!
}
在上面的例子中,我们定义了一个名为 performOperation
的函数,它接收一个无返回值的函数参数 operation
,并调用了该函数。通过将 sayHello
函数作为参数传递给 performOperation
,我们实现了函数的动态调用。在 main
函数中,通过调用 performOperation
并传递 sayHello
函数,实现了对函数作为参数的调用。
5. Dart函数与Java和Kotlin的对比
比较Dart函数与Java和Kotlin的对比时,可以关注以下几个方面的差异:
-
函数定义和调用的语法对比:Dart使用关键字
void
、int
、String
等来指定返回值类型,而Java和Kotlin使用返回类型的声明。在调用函数时,Dart使用functionName(arguments)
的方式,而Java和Kotlin使用functionName(arguments)
的方式。 -
函数作为一等公民的支持:Dart、Java和Kotlin都支持函数作为一等公民的概念,但在具体实现和用法上有所差异。
- Dart:函数是一等公民,可以作为参数传递给其他函数,也可以作为返回值返回。Dart中使用匿名函数和高阶函数的特性可以更方便地处理函数作为参数和返回值的情况。
- Java:虽然Java 8引入了Lambda表达式和函数式接口的概念,使得函数式编程风格更加便利,但Java中仍然需要使用接口或匿名类来模拟函数的行为。
- Kotlin:Kotlin天生支持函数作为一等公民,可以直接定义和使用匿名函数,使用lambda表达式简化函数的定义和调用。
-
函数式编程风格的对比:函数式编程强调函数的不可变性、纯函数、高阶函数和函数组合等特性。在这方面,Dart、Java和Kotlin的支持程度略有不同。
- Dart:Dart提供了匿名函数、高阶函数和闭包等特性,支持函数式编程风格,可以方便地使用函数组合、高阶函数和闭包实现函数的组合和处理。
- Java:Java通过Lambda表达式、函数式接口和Stream API等支持函数式编程,可以使用Lambda表达式和方法引用等简化函数的定义和使用。
- Kotlin:Kotlin内置了函数式编程的特性,包括Lambda表达式、高阶函数、扩展函数和集合操作符等,能够更自然地编写函数式风格的代码。
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题