Appearance
第10章:Dart 函数进阶
10.1 函数的定义与调用
在 Dart 中,函数是一等公民,可以作为变量、参数和返回值。
基本语法:
dart
returnType functionName(parameters) {
// 函数体
return value;
}示例:
dart
int add(int a, int b) {
return a + b;
}
void main() {
int result = add(5, 3);
print('5 + 3 = $result'); // 8
}10.2 函数参数类型
必选参数
必选参数是函数调用时必须提供的参数:
dart
void greet(String name, int age) {
print('Hello $name, you are $age years old');
}
void main() {
greet('John', 30); // 必须提供两个参数
}可选参数
位置可选参数
使用 [] 包裹的参数是位置可选参数:
dart
void greet(String name, [int age, String city]) {
if (age != null && city != null) {
print('Hello $name, you are $age years old from $city');
} else if (age != null) {
print('Hello $name, you are $age years old');
} else {
print('Hello $name');
}
}
void main() {
greet('John'); // 只提供必选参数
greet('John', 30); // 提供一个可选参数
greet('John', 30, 'New York'); // 提供所有参数
}命名可选参数
使用 {} 包裹的参数是命名可选参数:
dart
void greet(String name, {int age, String city}) {
if (age != null && city != null) {
print('Hello $name, you are $age years old from $city');
} else if (age != null) {
print('Hello $name, you are $age years old');
} else {
print('Hello $name');
}
}
void main() {
greet('John'); // 只提供必选参数
greet('John', age: 30); // 提供一个命名可选参数
greet('John', city: 'New York'); // 提供另一个命名可选参数
greet('John', age: 30, city: 'New York'); // 提供所有参数
}默认参数
可以为可选参数设置默认值:
dart
void greet(String name, {int age = 18, String city = 'Unknown'}) {
print('Hello $name, you are $age years old from $city');
}
void main() {
greet('John'); // 使用默认值
greet('John', age: 30); // 覆盖 age 的默认值
greet('John', city: 'New York'); // 覆盖 city 的默认值
greet('John', age: 30, city: 'New York'); // 覆盖所有默认值
}剩余参数
使用 ... 表示剩余参数,用于接收多个参数:
dart
void sum(int first, int second, [int... rest]) {
int total = first + second;
if (rest != null) {
for (int num in rest) {
total += num;
}
}
print('Sum: $total');
}
void main() {
sum(1, 2); // 2个参数
sum(1, 2, 3, 4, 5); // 多个参数
}10.3 匿名函数
匿名函数是没有名称的函数,也称为 lambda 或闭包:
dart
void main() {
// 匿名函数作为变量
var add = (int a, int b) {
return a + b;
};
int result = add(5, 3);
print('5 + 3 = $result');
// 匿名函数作为参数
List<int> numbers = [1, 2, 3, 4, 5];
numbers.forEach((number) {
print(number);
});
}10.4 箭头函数
箭头函数使用 => 语法,用于简化只有一条语句的函数:
dart
void main() {
// 箭头函数作为变量
var add = (int a, int b) => a + b;
int result = add(5, 3);
print('5 + 3 = $result');
// 箭头函数作为参数
List<int> numbers = [1, 2, 3, 4, 5];
numbers.forEach((number) => print(number));
// 箭头函数与条件表达式
var isEven = (int number) => number % 2 == 0;
print('Is 4 even? ${isEven(4)}');
print('Is 5 even? ${isEven(5)}');
}10.5 高阶函数
高阶函数是接收函数作为参数或返回函数的函数:
接收函数作为参数
dart
void operate(int a, int b, Function operation) {
int result = operation(a, b);
print('Result: $result');
}
void main() {
// 传递匿名函数
operate(5, 3, (a, b) => a + b); // 加法
operate(5, 3, (a, b) => a - b); // 减法
operate(5, 3, (a, b) => a * b); // 乘法
operate(5, 3, (a, b) => a / b); // 除法
}返回函数
dart
Function makeAdder(int addBy) {
return (int number) => number + addBy;
}
void main() {
var add5 = makeAdder(5);
var add10 = makeAdder(10);
print('5 + 5 = ${add5(5)}'); // 10
print('10 + 10 = ${add10(10)}'); // 20
}常用高阶函数
Dart 提供了许多常用的高阶函数,如 forEach、map、where、reduce 等:
dart
void main() {
List<int> numbers = [1, 2, 3, 4, 5];
// forEach:遍历列表
print('forEach:');
numbers.forEach((number) => print(number));
// map:转换列表元素
print('\nmap (squared):');
List<int> squared = numbers.map((number) => number * number).toList();
print(squared);
// where:筛选列表元素
print('\nwhere (even numbers):');
List<int> evenNumbers = numbers.where((number) => number % 2 == 0).toList();
print(evenNumbers);
// reduce:归约列表元素
print('\nreduce (sum):');
int sum = numbers.reduce((a, b) => a + b);
print(sum);
// fold:带初始值的归约
print('\nfold (sum with initial value 10):');
int sumWithInitial = numbers.fold(10, (a, b) => a + b);
print(sumWithInitial);
}运行结果:
forEach:
1
2
3
4
5
map (squared):
[1, 4, 9, 16, 25]
where (even numbers):
[2, 4]
reduce (sum):
15
fold (sum with initial value 10):
2510.6 闭包
闭包是一个函数对象,它可以访问其词法作用域之外的变量:
闭包的定义
dart
Function makeCounter() {
int count = 0;
return () {
count++;
return count;
};
}
void main() {
var counter = makeCounter();
print(counter()); // 1
print(counter()); // 2
print(counter()); // 3
// 创建另一个计数器
var counter2 = makeCounter();
print(counter2()); // 1
print(counter2()); // 2
}闭包的原理
闭包能够访问其词法作用域之外的变量,是因为它捕获了这些变量的引用,而不是值。即使创建闭包的函数已经执行完毕,闭包仍然可以访问这些变量。
闭包的应用场景
- 封装私有变量:
dart
Function makePerson(String name) {
int age = 0;
return (int newAge) {
age = newAge;
print('$name is now $age years old');
};
}
void main() {
var updateJohn = makePerson('John');
updateJohn(30); // John is now 30 years old
updateJohn(31); // John is now 31 years old
}- 延迟执行:
dart
Function makeDelayedFunction(String message) {
return () {
print(message);
};
}
void main() {
var hello = makeDelayedFunction('Hello, Dart!');
// 稍后执行
hello(); // Hello, Dart!
}- 函数工厂:
dart
Function makeMultiplier(int factor) {
return (int number) => number * factor;
}
void main() {
var doubleIt = makeMultiplier(2);
var tripleIt = makeMultiplier(3);
print(doubleIt(5)); // 10
print(tripleIt(5)); // 15
}10.7 实操案例
用高阶函数、闭包简化代码,实现数据处理:
数据过滤与转换
dart
void main() {
List<Map<String, dynamic>> users = [
{'name': 'John', 'age': 30, 'gender': 'male', 'score': 85},
{'name': 'Alice', 'age': 25, 'gender': 'female', 'score': 92},
{'name': 'Bob', 'age': 35, 'gender': 'male', 'score': 78},
{'name': 'Jane', 'age': 28, 'gender': 'female', 'score': 95},
{'name': 'Tom', 'age': 40, 'gender': 'male', 'score': 88}
];
// 1. 过滤出女性用户
List<Map<String, dynamic>> femaleUsers = users.where((user) => user['gender'] == 'female').toList();
print('Female users:');
femaleUsers.forEach((user) => print('${user['name']}, ${user['age']}'));
// 2. 过滤出年龄大于30的用户
List<Map<String, dynamic>> olderUsers = users.where((user) => user['age'] > 30).toList();
print('\nUsers older than 30:');
olderUsers.forEach((user) => print('${user['name']}, ${user['age']}'));
// 3. 计算所有用户的平均分数
double averageScore = users.map((user) => user['score']).reduce((a, b) => a + b) / users.length;
print('\nAverage score: ${averageScore.toStringAsFixed(2)}');
// 4. 转换用户列表为仅包含姓名和分数的列表
List<Map<String, dynamic>> userScores = users.map((user) {
return {'name': user['name'], 'score': user['score']};
}).toList();
print('\nUser scores:');
userScores.forEach((user) => print('${user['name']}: ${user['score']}'));
// 5. 按分数排序
userScores.sort((a, b) => b['score'].compareTo(a['score']));
print('\nUser scores sorted by score (descending):');
userScores.forEach((user) => print('${user['name']}: ${user['score']}'));
}运行结果:
Female users:
Alice, 25
Jane, 28
Users older than 30:
Bob, 35
Tom, 40
Average score: 87.60
User scores:
John: 85
Alice: 92
Bob: 78
Jane: 95
Tom: 88
User scores sorted by score (descending):
Jane: 95
Alice: 92
Tom: 88
John: 85
Bob: 78函数工厂与闭包
dart
// 函数工厂:创建不同类型的计算器
Function createCalculator(String operation) {
switch (operation) {
case 'add':
return (num a, num b) => a + b;
case 'subtract':
return (num a, num b) => a - b;
case 'multiply':
return (num a, num b) => a * b;
case 'divide':
return (num a, num b) => a / b;
default:
throw ArgumentError('Unknown operation');
}
}
// 闭包:创建带记忆功能的计算函数
Function createMemoizedFunction(Function operation) {
Map<String, dynamic> cache = {};
return (dynamic a, dynamic b) {
String key = '$a-$b';
if (cache.containsKey(key)) {
print('Using cached result for $a and $b');
return cache[key];
} else {
dynamic result = operation(a, b);
cache[key] = result;
print('Computing result for $a and $b');
return result;
}
};
}
void main() {
// 创建计算器
var add = createCalculator('add');
var subtract = createCalculator('subtract');
var multiply = createCalculator('multiply');
var divide = createCalculator('divide');
print('5 + 3 = ${add(5, 3)}');
print('5 - 3 = ${subtract(5, 3)}');
print('5 * 3 = ${multiply(5, 3)}');
print('5 / 3 = ${divide(5, 3)}');
// 创建带记忆功能的加法函数
var memoizedAdd = createMemoizedFunction(add);
print('\nMemoized add:');
print('5 + 3 = ${memoizedAdd(5, 3)}'); // 第一次计算
print('5 + 3 = ${memoizedAdd(5, 3)}'); // 使用缓存
print('10 + 20 = ${memoizedAdd(10, 20)}'); // 第一次计算
print('10 + 20 = ${memoizedAdd(10, 20)}'); // 使用缓存
}运行结果:
5 + 3 = 8
5 - 3 = 2
5 * 3 = 15
5 / 3 = 1.6666666666666667
Memoized add:
Computing result for 5 and 3
5 + 3 = 8
Using cached result for 5 and 3
5 + 3 = 8
Computing result for 10 and 20
10 + 20 = 30
Using cached result for 10 and 20
10 + 20 = 30