函数 , 自定义方法 , 方法的传参 , 可选参数和命名参数 , 给方法传入方法 , 箭头函数 , 函数的相互调用 , 匿名方法 , 自执行方法 , 方法的递归 , 全局变量和局部变量 , 闭包
函数
自定义方法
Dart自带的函数为内置函数 例如:
1
2
3void main(){
print('print是内置函数');
}自定义方法的基本格式 例如:
1
2
3
4
5
6
7返回类型 方法名称 (参数1...){
方法体
return 返回值;
}
void printInfo(){ //自定义方法方法名
print('我是一个自定义方法'); //方法体
}自定义方法可以在入口方法之外定义,也可以在入口以内定义,但调用必须在入口以内调用
一个方法可以嵌套另外一个方法
例1:在入口方法内调用自定义函数
1
2
3
4
5
6void printInfo(){
print('我是一个自定义方法');
}
main(){
printInfo();
} //输出: 我是一个自定义方法例2:吧指定类型的myNum返回到getNum方法并打印输出
1
2
3
4
5
6
7
8
9main(){
int getNum(){ //指定返回类型为int类型,非int类型会报错,返回类型也可以是List,String
var myNum=123; //定义myNum=123
return myNum; //吧myNum的值返回给getNum
}
var n=getNum(); //吧getNum方法赋值给n
print(n); //打印n输出: 123
print(getNum()); //因为吧myNum的值返回给了getNum所以也可以直接打印getNum 输出: 123
}例3:返回值固定为String
1
2
3
4String tast(){
return '你好';
}
print(tast());以上举例中的方法全都为‘全作用域‘,可以在入口方法内使用
如果是在’①自定义方法中自定义的②方法‘则为‘局部作用域’,仅可在①(本自定义方法的上层自定义方法)中使用
例如:
1
2
3
4
5void xxx(){
aaa(){
print('这是一个局部作用域方法');
}
}
方法的传参
形参:出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用
- 形参可以有多个,形参可以固定类型
实参:出现在主调函数中,进入被调函数后,实参变量也不能使用
形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
例1:定义一个方法,求1到n的所有数的和
1
2
3
4
5
6
7
8
9
10int myNum(int n){ //形参n,返回类型为int
var sum=0;
for(int i=0;i<=n;i++){
sum+=i;
}
return sum;
}
var n=myNum(100); //100为实参,给方法myNum的形参n传入参数100,赋值给n
print(n); //输出: 5050
print(myNum(60)); //给方法myNum的形参n传入实参60并打印输出: 1830例2:定义一个方法,打印用户信息
1
2
3
4
5String printUserInfo(String user,int age){
return '姓名:$user-----年龄:$age';
}
var p=printUserInfo('老念',20);
print(p);
可选参数和命名参数
使用[ ]定义可选参数,可选参数放在参数的最后,用逗,号分隔
一般参数是在调用时必须传入实参,可选参数为可填可不填
可以有多个可选参数
传入实参时必须按照定义参数的顺序填写
例1:定义一个可选参数
1
2
3
4
5
6
7
8
9
10
11String printUserInfo(String user,int age,[String sex]){ //可选参数sex
if(sex!=null){ //如果sex不等于null,则执行下面的内容null:不存在,空
return '姓名:$user----年龄:$age----性别:$sex';
}else{ //否则执行下面内容,就是如果可选参数sex是空的,则在下面输出时候打印出 性别保密
return '姓名:$user----年龄:$age----性别保密'
}
}
var p=printUserInfo('老念',25);
var f=printUserInfo('张三',35,'男');
print(p); //输出: 姓名:老念----年龄:25----性别保密
print(f); //输出: 姓名:张三----年龄:35----性别:男例2:定义一个带默认参数的可选参数
1
2String printUserInfo(String user,[String sex='男',int age])
//如果没有赋予sex实参,则默认为'男',如果赋予了参数,则将覆盖默认参数例3:定义一个命名参数{ }
- 命名参数同时也是可选参数也可以指定默认参数
- 命名参数可有多个
- 命名参数在传参时只要带上名字,可以不按定义参数的顺序填写,所以如果需要多个可选参数的情况下最好使用命名参数的方式定义
1
2
3
4
5
6
7String printUserInfo(String user, {int age, String sex = '男'}) { //使用大括号定义一个命名参数age,和一个带默认参数的命名参数sex
return '姓名:$user---年龄:$age---性别:$sex';
}
var p = printUserInfo('张三', sex: '女'); //命名参数必须带上名字比如sex:'女',
var f = printUserInfo('张三', age: 20); //命名参数可不按定义顺序传入,同时默认参数也会生效
print(p); //输出: 姓名:张三---年龄:null---性别:女
print(f); //输出: 姓名:张三---年龄:20---性别:男
给方法传入方法
如何实现一个把方法当做参数的方法 例如:
1
2
3
4
5
6
7fn1(){ //自定义方法fn1,方法体为输出fn1
print('fn1');
}
fn2(fn){ //自定义方法fn2,方法体为运行形参处传入的实参方法
fn();
}
fn2(fn1); //调用fn2传入实参fn1就会执行fn1方法体输出: fn1
箭头函数
箭头函数只能写一行,箭头函数不能写多句话
箭头函数一定要带箭头=>,箭头函数可以使用三目运算的方法写
例1:使用forEach循环遍历list,然后简化为箭头函数
1
2
3
4
5
6
7List list=[1,2,3];
list.forEach((value){
print(value);
}); //输出: 1 2 3
----------------------------------------
List list=[1,2,3];
list.forEach((value)=>print(value)); //简化为箭头函数,输出: 1 2 3例2:修改数组中的数据,让数组中大于2的数值乘以2,然后简化为箭头函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14List list=[1,2,3,4,5];
var newlist=list.map((value){
if(value>2){
return value*2;
}else{
return value;
}
});
print(newlist.toList()); //输出: [1, 2, 6, 8, 10]
----------------------------------------
List list=[1,2,3,4,5];
var newlist=list.map((value)=>value>2?value*2:value);
print(newlist.toList()); //输出: [1, 2, 6, 8, 10]
//因为箭头函数只能写一行所以使用三目运算,=>为箭头函数,三目运算中?为if,:为else
函数的相互调用
函数之间的调用例如:
例:自定义方法aNum来判断一个数是否为偶数,自定义方法bNum,在自定义方法bNum中调用自定义方法aNum来打印1~n之间所有偶数
1
2
3
4
5
6
7
8
9
10
11
12
13
14bool aNum(int n){ //bool类型自定义方法,形参为int n,
if(n%2==0){ //如果n是偶数则返回true给aNum
return true;
} //else可以不写,也不用写大括号
return false; //否则返回false
}
bNum(int n){ //自定义方法bNum,形参为int n
for(int i=1;i<=n;i++){ //for循环
if(aNum(i)){ //调用aNum吧i当做形参填入,判断i是否为偶数
print(i); //如果是偶数,打印i,否则跳过
}
}
}
bNum(10); //bNum(10)实参为10,则for循环中的n就是10 输出: 2 4 6 8 10
匿名方法
匿名方法就是没有方法名称的方法
匿名方法的传参使用和一般方法一样
例1:匿名方法定义方法
1
2
3
4var printNum=(){ //这是一个匿名方法被赋值给了printNum
print(123);
};
printNum(); //调用printNum方法可以 输出: 123例2:匿名方法的传参
1
2
3
4var printNum=(int n){
print(n*2);
};
printNum(5); //输出: 10
自执行方法
自执行方法((){})():指不需要调用也会自动执行的方法
自执行方法也可以传入参数
例1:自执行方法
1
2
3((){
print('这是一个自执行方法');
})(); //输出: 这是一个自执行方法例2:给自执行方法传入参数
1
2
3((int n){
print(n);
})(12); //输出: 12
方法的递归
递归其实是方法自己调用自己
在递归中遇到return停止执行
例1:使用递归达成1~5的阶乘 1*2 * 3 *4 *5
1
2
3
4
5
6
7
8
9
10var sum=1;
fn(n){
sum*=n; //sum=sum*n
if(n==1){ //如果n=1则停止执行
return;
}
fn(n-1); //否则n-1继续执行
}
fn(5); //fn传入参数5
print(sum); //输出: 120例2:求1~100的和
1
2
3
4
5
6
7
8
9
10var sum=0;
fn(n){
sum+=n;
if(n==1){
return;
}
fn(n-1);
}
fn(100);
print(sum); //输出: 5050
闭包
全局变量和局部变量
全局变量: 全局变量作用域大,常驻内存,污染全局
例:全局变量
1
2
3
4
5
6
7
8
9
10var a=1; //全局变量,全局作用域
main() {
print(a); //输出: 1
fn(){ //自定义方法fn
a++; //方法体是a++然后打印出a
print(a);
}
fn(); //因a全局作用域,所以常驻内存污染全局因此a=1的情况下a++=2 输出: 2
fn(); //因a全局作用域,所以常驻内存污染全局因此a=2的情况下a++=3 输出: 3
} //如果继续调用fn,那么会持续向下加局部变量: 作用域小,不会常驻内存,会被垃圾回收机制回收,不会污染全局
例:局部变量
1
2
3
4
5
6
7
8
9
10main() {
printInfo(){ //自定义方法
var myNum=1; //自定义方法中的局部变量
myNum++; //自增
print(myNum); //调用方法时打印出自增后的myNum
}
printInfo(); //调用该方法,自增后值为2 输出: 2
printInfo(); //因为是局部变量,没有常驻内存,每次的值都会被垃圾回收机制回收,所以值依旧是1自增为2 输出: 2
print(myNum); //因为是局部变量,作用域小,所以在自定义方法外调用自定义方法中的属性是无法调用的 错误写法X
}
闭包
闭包是一种在全局变量和局部变量之间取舍的写法,闭包常驻内存并且不会污染全局
闭包:函数嵌套函数,内部函数会调用外部函数的变量或参数,不会被系统回收
闭包写法:函数嵌套函数并return里面的函数
例如:
1
2
3
4
5
6
7
8
9
10
11
12
13main() {
fn(){
var a=1;
return(){
a++;
print(a);
};
}
var b=fn();
b(); //输出: 2
b(); //输出: 3
b(); //输出: 4
}