今天我们要学习 Dart 中代码复用的最小单位 ——函数。函数就像一个个 “代码模块”,能把重复使用的逻辑封装起来,让程序更简洁、更易维护。
一、函数定义:基本结构与规范
函数是执行特定任务的代码块,在 Dart 中,函数的定义需要明确返回值类型、函数名、参数列表和函数体。
1. 基本语法
返回值类型 函数名(参数列表) {
// 函数体(执行的代码)
return 返回值; // 与返回值类型匹配
}
2. 详细说明
-
返回值类型:
- 若函数有返回值,需指定具体类型(如
int、String等)。 - 若没有返回值,可省略或指定为
void。
- 若函数有返回值,需指定具体类型(如
-
函数名:
- 遵循小驼峰命名法(首字母小写,后续单词首字母大写),如
calculateSum、printMessage。 - 命名需清晰表达函数功能,避免模糊的名称(如
doSomething)。
- 遵循小驼峰命名法(首字母小写,后续单词首字母大写),如
-
参数列表:
- 由 “参数类型 参数名” 组成,多个参数用逗号分隔。
- 是函数接收外部数据的入口。
示例 1:有返回值的函数
// 定义一个计算两个整数之和的函数
int calculateSum(int a, int b) {
int result = a + b;
return result; // 返回计算结果(int类型)
}
void main() {
int sum = calculateSum(3, 5); // 调用函数,传入参数3和5
print("和为:$sum"); // 输出:和为:8
}
示例 2:无返回值的函数(void)
// 定义一个打印信息的函数
void printMessage(String name) {
print("Hello, $name!"); // 没有return语句
}
void main() {
printMessage("Dart"); // 调用函数,传入参数"Dart"
// 输出:Hello, Dart!
}
3. 函数的简化写法
当函数体只有一行返回语句时,可省略大括号和 return,直接用箭头 => 连接:
// 简化版的求和函数
int calculateSum(int a, int b) => a + b;
// 简化版的打印函数(void函数也可简化)
void printMessage(String name) => print("Hello, $name!");
二、可选参数:让函数更灵活
在某些场景下,函数的参数可能不是必须的(比如可选的配置项)。Dart 提供了两种可选参数:位置可选参数和命名可选参数。
1. 位置可选参数([] 包裹)
- 用方括号
[]包裹参数,放在必选参数之后。 - 调用时可省略,若省略则使用默认值(若未指定默认值,则为
null)。 - 传递参数时需按位置顺序对应。
示例:带默认值的位置可选参数
// 定义一个计算商品总价的函数:单价(必选)+ 数量(可选,默认1)+ 折扣(可选,默认0)
double calculateTotal(double price, [int count = 1, double discount = 0.0]) {
double total = price * count * (1 - discount);
return total;
}
void main() {
// 情况1:只传必选参数(单价)
double total1 = calculateTotal(100.0);
print("总价1:$total1"); // 输出:总价1:100.0(数量1,无折扣)
// 情况2:传必选参数+第一个可选参数(数量)
double total2 = calculateTotal(100.0, 2);
print("总价2:$total2"); // 输出:总价2:200.0(数量2,无折扣)
// 情况3:传所有参数
double total3 = calculateTotal(100.0, 2, 0.1);
print("总价3:$total3"); // 输出:总价3:180.0(数量2,9折)
}
2. 命名可选参数({} 包裹)
- 用大括号
{}包裹参数,通常指定默认值(否则可能为null)。 - 调用时需用 “参数名:值” 的形式传递,不依赖位置顺序。
- 更适合参数较多的场景,提高代码可读性。
示例:命名可选参数
// 定义一个创建用户信息的函数:姓名(必选)+ 年龄(可选)+ 邮箱(可选)
String createUser(String name, {int? age, String? email}) {
String info = "姓名:$name";
if (age != null) info += ",年龄:$age";
if (email != null) info += ",邮箱:$email";
return info;
}
void main() {
// 情况1:只传必选参数
String user1 = createUser("张三");
print(user1); // 输出:姓名:张三
// 情况2:传必选参数+邮箱(跳过年龄)
String user2 = createUser("李四", email: "lisi@example.com");
print(user2); // 输出:姓名:李四,邮箱:lisi@example.com
// 情况3:传所有参数(顺序无关)
String user3 = createUser("王五", age: 25, email: "wangwu@example.com");
print(user3); // 输出:姓名:王五,年龄:25,邮箱:wangwu@example.com
}
小贴士:实际开发中,命名可选参数更常用,因为参数名明确,不易出错。
三、匿名函数:没有名字的函数
匿名函数就是没有函数名的函数,通常用于临时定义简单逻辑,作为参数传递给其他函数。
1. 基本语法
(参数列表) {
// 函数体
};
// 或简化为(单行时)
(参数列表) => 表达式;
2. 常见用法:作为参数传递
在集合的 forEach、map 等方法中,经常使用匿名函数:
示例 1:遍历集合时使用匿名函数
void main() {
List<String> fruits = ['苹果', '香蕉', '橙子'];
// 用匿名函数作为forEach的参数
fruits.forEach((fruit) {
print("水果:$fruit");
});
// 输出:
// 水果:苹果
// 水果:香蕉
// 水果:橙子
}
示例 2:临时计算逻辑
void main() {
// 定义一个接收函数作为参数的函数
void calculateAndPrint(int a, int b, Function operation) {
dynamic result = operation(a, b); // 调用传入的函数
print("结果:$result");
}
// 传递匿名函数(加法)
calculateAndPrint(5, 3, (x, y) => x + y); // 输出:结果:8
// 传递另一个匿名函数(乘法)
calculateAndPrint(5, 3, (x, y) => x * y); // 输出:结果:15
}
四、立即执行函数:定义后马上运行
立即执行函数(IIFE,Immediately Invoked Function Expression)是定义后立即调用的函数,通常用于隔离作用域(避免变量污染)。
1. 语法与示例
在函数定义后直接加 () 传入参数,即可立即执行:
void main() {
// 立即执行函数(无参数)
(() {
print("这个函数会立即执行!");
})();
// 输出:这个函数会立即执行!
// 带参数的立即执行函数
((String message) {
print("消息:$message");
})("Hello, IIFE!");
// 输出:消息:Hello, IIFE!
// 立即执行函数的返回值可以被接收
int result = ((int a, int b) => a + b)(10, 20);
print("立即计算的和:$result"); // 输出:立即计算的和:30
}
2. 作用:隔离变量作用域
立即执行函数内部的变量不会影响外部:
void main() {
// 外部变量
int x = 10;
// 立即执行函数
(() {
int x = 20; // 内部变量,与外部x无关
print("内部x:$x"); // 输出:内部x:20
})();
print("外部x:$x"); // 输出:外部x:10(不受内部影响)
}
五、函数的其他特性
1. 函数作为返回值
函数可以作为另一个函数的返回值,这在高阶函数中很常见:
// 定义一个返回函数的函数
Function makeAdder(int increment) {
return (int number) => number + increment; // 返回一个匿名函数
}
void main() {
// 获取一个“加5”的函数
var add5 = makeAdder(5);
print(add5(10)); // 输出:15(10 + 5)
// 获取一个“加10”的函数
var add10 = makeAdder(10);
print(add10(10)); // 输出:20(10 + 10)
}
2. 函数参数的类型限制
为了增强类型安全,可指定函数参数的类型(如 int Function(int, int) 表示接收两个 int 参数并返回 int 的函数):
// 定义一个接收特定类型函数的函数
int calculate(int a, int b, int Function(int, int) operation) {
return operation(a, b);
}
void main() {
// 传递符合类型要求的函数(加法)
int sum = calculate(3, 4, (x, y) => x + y);
print(sum); // 输出:7
// 传递乘法函数
int product = calculate(3, 4, (x, y) => x * y);
print(product); // 输出:12
}