介绍
函数是可读,可维护和可重用代码的构建块。 函数是一组用于执行特定任务的语句。 函数将程序组织成逻辑代码块。 一旦定义,可以调用函数来访问代码。 这使得代码可以重用。 此外,函数可以轻松读取和维护程序的代码。
函数这块的话没啥好讲的,我主要通过例子的方式来跟大家讲解,相信大家看了就会明白,不明白的可以直接留言,我会及时回复的
函数
普通函数与 Lambda 函数的定义的方式
// 推荐
int add(int x, int y) {
return x + y;
}
// 函数定义可省略类型,但并不推荐
add1(x, y) {
return x + y;
}
// 当函数体内只有一个表达式的时候可以使用:
//语法 [return_type]function_name(parameters)=>expression;
int add2(int x, int y) => x + y;
print(add(1, 2));
注意:所有的函数都返回一个值。如果没有指定返回值,则 默认把语句 return null; 作为函数的最后一个语句执行
可选参数
可选命名参数:使用 {param1, param2, …}
的形式来指定命名参数
int add({int x, int y}) {
x ??= 1;
y ??= 2;
return x + y;
}
print(add(x:2, y:4)); // 6
print(add()); // 3;
在这里我们在函数体内 x ??= 1
是因为这个函数是可选参数,如果没有这个参数我们直接 return x + y 会报错的
提示很明确: 无法读取null的属性,大家需要多多注意啊
可选位置参数:把可选参数放到 []
中,必填参数要放在可选参数前面
int add(int x, [int y, int z]) {
y ??= 2;
z ??= 3;
return x + y + z;
}
print(add(1)); // 6
print(add(1, 3, 4)); // 8
可选命名参数默认值(默认值必须是编译时常量), 目前可以使用等号 '='
或冒号 ':'
int add(int x, {int y = 2, int z = 3}) => x + y + z;
print(add(1)); // 6
print(add(1, y: 5)); // 9
Dart SDK 1.21 之前只能用冒号,冒号的支持以后会移除,所以建议使用等号
可选位置参数默认值(默认值必须是编译时常量),只能使用等号 '='
int add(int x, [int y = 2, int z = 3]) => x + y + z;
print(add(1)); // 6
print(add(1, 3, 5)); // 9
匿名函数
匿名函数的参照如下:
([[Type] param1[, …]]) {
codeBlock;
};
匿名函数,顾名思义就是没有名字的函数
无参匿名函数:
var info = () => print('这是无参匿名函数');
info(); // 这是无参数匿名函数
有参匿名函数:
var info = (name) => 'I am $name';
print(info('gaozan')); // I am gaozan
List.forEach() 就用的匿名函数
List list = [1, 2, 3];
list.forEach((item) => print('$item'));
通常不希望再次使用(即只使用一次的)的函数可以定义为匿名函数
扩展: 如果还是想再次使用匿名函数的话, 也有方法, 像我们上方的例子一样。可赋值给变量,通过变量调用
闭包
-
闭包是一个方法(对象)
-
闭包定义在其他方法内部
-
闭包能够访问外部方法内的局部变量,并持有其状态(这是闭包最大的作用,可以通过闭包的方式,将其暴露出去,提供给外部访问)
返回Function对象(闭包)下面有一个例子:
Function makeAddFunc(int x) {
x++;
return (int y) => x + y;
}
main() {
var addFunc1 = makeAddFunc(2);
var addFunc2 = makeAddFunc(4);
print(addFunc1(3)); // 6
print(addFunc2(3)); // 8
}
...
// 大家可以先想一想结果为什么是 6 和 8 ?
画图一向丑,不要介意。不明白直接留言,知无不言
函数别名
普通的函数定义。在赋值之后,会丢失函数签名信息。
使用typedef 给函数起一个别名,使用比较方便。例如定义一个方法的回调,直接使用别名定义
void main() {
// 函数别名
MyAlias myAlias;
// 可以指向任何同签名的函数
myAlias = subtsract;
myAlias(4, 2); // subtsract: 2
myAlias = divide;
myAlias(4, 2); // divide: 2
// typedef 作为参数传递给函数
calculator(4, 2, subtsract); // subtsract: 2
}
// 函数别名
typedef MyAlias(int a, int b);
// 根据MyAlias相同的函数签名定义两个函数
subtsract(int a, int b) {
print('subtsract: ${a - b}');
}
divide(int a, int b) {
print('divide: ${a / b}');
}
// typedef 也可以作为参数传递给函数
calculator(int a, int b, MyAlias func) {
func(a, b);
}
再来个好玩的,我就不讲了哈,Demo3 大家自己玩一玩,可以贴到留言里哈
void main() { // 主入口
Fun1 fun1;
fun1 = add;
Demo1(fun1, 1, 2); // sum1 = 3
Demo2(fun1, 1, 2); // sum2 = 3
// Demo3() ... ???
}
typedef Fun1(int a, int b);
typedef Fun2<T, K>(T a, K b);
int add(int a, int b) {
print('a + b');
return a + b;
}
Demo1(int f(int a, int b), int x, int y) {
var sum = f(x, y);
print("sum1 = $sum");
}
Demo2(Fun1 f, int x, int y) {
var sum = f(x, y);
print("sum2 = $sum");
}
Demo3(Fun2<int, int> f, int x, int y) {
var sum = f(x, y);
print("sum3 = $sum");
}
函数递归
递归这个没啥好讲的,跟其他语言都差不多,留一个例子,通过方法的递归求和
main() {
var sum = 0;
fn(int n) {
sum += n;
if (n == 0) {
return;
}
fn(n - 1);
}
fn(100);
print(sum);
}