前言
在编程世界中,函数是构建逻辑的核心单元,而Dart作为一门现代化的多范式语言,其函数设计既灵活又强大,能够同时满足面向对象和函数式编程的需求。无论是开发Flutter应用,还是编写服务端脚本,深入理解Dart函数都能显著提升代码的可读性与效率。
一、函数的定义
一个函数由函数签名+函数体组成。
1.1、基本语法
函数通常由函数返回类型 + 函数名 + 参数 + 函数体组成。
- 函数返回类型:需与return 返回的数据类型保持一致。
- 函数名:遵循标识符命名规范,一般使用小驼峰命名(首字母小写,后续首字母大写)。
- 参数:规定需要传入函数进行使用的数据类型。
- 函数体:实际执行的代码块。
示例:
Dart
int addOne(int a){
a++;
return a;
}
注:函数签名包括函数返回类型、函数名、参数。
1.2、参数
Dart中函数的参数支持多种方式。分别为:
- 必须参数:调用函数时必须传入的参数。
- 可选参数:调用函数时可根据需要进行传入的参数,置于参数列表尾部。
- 位置参数:一种简化的可选参数形式,调用时位置顺序不能更改。
- 默认参数:为可选参数和位置参数提供默认值。
必须参数示例:
Dart
// name必须参数,调用hello函数时必须传入。
void hello(String name) {
print('hello,$name!');
}
void main() {
hello('Dart'); // 输出:hello,Dart!
}
可选参数示例:用大括号({})进行包裹。
Dart
// age为可空类型,意味着可以不进行传入。
void introduce(String name,{int? age,required sex}){
print('hello,my name is $name');
if (sex){
print('I am a boy');
}else{
print('I am a girl');
}
if (age!=null) {
print('I am $age years old this year');
}
}
void main() {
introduce('小明',sex:true); // 没有传入age,则age为空,结果不打印。
// 输出:
// hello,my name is 小明
// I am a boy
}
位置参数示例:用中括号([])进行包裹。
Dart
void introduce(String name,[int? age,sex]){
print('hello,my name is $name');
if (sex!=null){
print('I am a $sex');
}
if (age!=null) {
print('I am $age years old this year');
}
}
void main() {
introduce('小明'); // 输出:hello,my name is 小明
introduce('小明',18,'boy');
// 输出:
// hello,my name is 小明
// I am a boy
// I am 18 years old this year
}
默认参数示例:为可选参数提供默认值。
Dart
// age为默认值参数,在调用函数时不传入age参数时age为18
void introduce(String name,[age=18,sex]){
print('hello,my name is $name');
if (sex!=null){
print('I am a $sex');
}
if (age!=null) {
print('I am $age years old this year');
}
}
void main() {
introduce('小明');
// 输出:
// hello,my name is 小明
// I am 18 years old this year
}
注意:可选参数,位置参数的数据类型会进行自动推断,意味着定义函数时可以不进行类型声明。
1.3、返回值
Dart中函数的返回值可以是没有返回值。 也可以是返回单个值或多个值(以列表或映射形式返回)。
示例:返回单个值。
Dart
int addOne(int a){
a++;
return a;
}
示例:返回多个值。
Dart
List<int> getList(int a, int b){
return [a,a*2];
}
Map<String,int> getMap(String a, int b){
return {a:b};
}
二、匿名函数
匿名函数就如同其名字一样是没有名字的函数。这是一种简化定义函数的方式,通常在函数作为参数时传参使用。
由圆括号()+大括号{}组成
示例:
Dart
void executeFunc(void Function() func){
func(); // 调用传入的函数
}
void main() {
executeFunc(
() {print('hello,Dart!'); // 匿名函数
}); // 输出:hello,Dart!
}
箭头函数,一种特殊的匿名函数,用于执行只有一行的代码,自动返回结果。
由 => 声明
示例:
Dart
void main() {
var add = (int a, int b) => a + b;
print(add.runtimeType); // 输出:(int, int) => int
print(add(2,4));// 输出:6
}
三、闭包
闭包可以理解为函数中嵌套函数,这样做可以带来的好处是内部的函数可以访问外部的作用域。常用于捕获外部作用域的变量。
示例:
Dart
Function outerFunc(){
int outerFuncData = 1; // 外部函数的作用域
int innerFunc(){
return ++outerFuncData; // 访问外部函数作用域的变量outerFuncData
}
return innerFunc;
}
void main() {
var a = outerFunc(); // a为outerFunc函数返回的结果,其结果为函数类型。
print(a.runtimeType); // 输出:() => int
print(a()); // 输出:2
print(a()); // 输出:3
}
四、高阶函数
高阶函数是可以接受函数作为参数或返回值的函数。如上面的匿名函数示例将函数作为参数进行传递。
示例:
Dart
// executeFunc函数为高阶函数,其接受传入参数为函数类型。
void executeFunc(void Function() func){
func(); // 调用传入的函数
}
void main() {
executeFunc(
() {print('hello,Dart!');
}); // 输出:hello,Dart!
}
五、回调函数
回调函数是作为参数传递给另一个函数的函数,就和其名字一样往回调用函数。其场景是在将函数作为参数时,在调用函数内部执行传入的函数参数。
示例:
Dart
void executeFunc(void Function() func){
func(); // 执行回调函数
}
void main() {
executeFunc(
() {print('hello,Dart!'); // 匿名函数,也是回调函数。其作为参数传递给另一个函数。
}); // 输出:hello,Dart!
}
六、递归函数
递归函数可以理解为函数自己调用自己。因其执行过程包括递和归两个过程,故称其为递归函数。
- 递:深入最里层叫做递。
- 归:遇到递的终止条件返回时叫做归。
注意:递归函数必须有一个明确的终止条件,否则会导致无限递归。
示例:
Dart
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
void main() {
print(factorial(5));// 输出:120
}
//详细执行流程说明
//1.初始执行
int factorial(int 5) {
if (n == 0 || n == 1) {
return 1;
} else {
//2.第一次递归调用
return 5*factorial(int 4) {
if (n == 0 || n == 1) {
return 1;
} else {
//3.第二次递归调用
return 4*factorial(int 3) {
if (n == 0 || n == 1) {
return 1;
} else {
//4.第三次递归调用
return 3*factorial(int 2) {
if (n == 0 || n == 1) {
return 1;
} else {
//5.第四次递归调用
return 2*factorial(int 1) {
if (n == 0 || n == 1) {
return 1;
} else {
return n* factorial(n-1);
}
}
}
}
}
}
}
}
}
}
七、总结
本小节从基础函数定义出发,逐步解析Dart中的高阶函数、匿名函数、闭包等核心概念,并通过实例演示如何实现代码结构。相信通过本小节的了解,我们将会很快的掌握Dart中的函数。