0%

Dart学习笔记 (五)

函数 , 自定义方法 , 方法的传参 , 可选参数和命名参数 , 给方法传入方法 , 箭头函数 , 函数的相互调用 , 匿名方法 , 自执行方法 , 方法的递归 , 全局变量和局部变量 , 闭包

函数

自定义方法

  • Dart自带的函数为内置函数 例如:

    1
    2
    3
    void main(){
    print('print是内置函数');
    }
  • 自定义方法的基本格式 例如:

    1
    2
    3
    4
    5
    6
    7
    返回类型 方法名称 (参数1...){
    方法体
    return 返回值;
    }
    void printInfo(){ //自定义方法方法名
    print('我是一个自定义方法'); //方法体
    }
  • 自定义方法可以在入口方法之外定义,也可以在入口以内定义,但调用必须在入口以内调用

  • 一个方法可以嵌套另外一个方法

    例1:在入口方法内调用自定义函数

    1
    2
    3
    4
    5
    6
    void printInfo(){
    print('我是一个自定义方法');
    }
    main(){
    printInfo();
    } //输出: 我是一个自定义方法

    例2:吧指定类型的myNum返回到getNum方法并打印输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    main(){
    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
    4
    String tast(){
    return '你好';
    }
    print(tast());
  • 以上举例中的方法全都为全作用域,可以在入口方法内使用

  • 如果是在’①自定义方法中自定义的②方法‘则为‘局部作用域’,仅可在①(本自定义方法的上层自定义方法)中使用

    例如:

    1
    2
    3
    4
    5
    void xxx(){
    aaa(){
    print('这是一个局部作用域方法');
    }
    }

方法的传参

  • 形参:出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用

    • 形参可以有多个,形参可以固定类型
  • 实参:出现在主调函数中,进入被调函数后,实参变量也不能使用

  • 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

  • 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

  • 例1:定义一个方法,求1到n的所有数的和

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int 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
    5
    String 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
    11
    String 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
    2
    String printUserInfo(String user,[String sex='男',int age])   
    //如果没有赋予sex实参,则默认为'男',如果赋予了参数,则将覆盖默认参数

    例3:定义一个命名参数{ }

    • 命名参数同时也是可选参数也可以指定默认参数
    • 命名参数可有多个
    • 命名参数在传参时只要带上名字,可以不按定义参数的顺序填写,所以如果需要多个可选参数的情况下最好使用命名参数的方式定义
    1
    2
    3
    4
    5
    6
    7
    String 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
    7
    fn1(){                    //自定义方法fn1,方法体为输出fn1
    print('fn1');
    }
    fn2(fn){ //自定义方法fn2,方法体为运行形参处传入的实参方法
    fn();
    }
    fn2(fn1); //调用fn2传入实参fn1就会执行fn1方法体输出: fn1

箭头函数

  • 箭头函数只能写一行,箭头函数不能写多句话

  • 箭头函数一定要带箭头=>,箭头函数可以使用三目运算的方法写

    例1:使用forEach循环遍历list,然后简化为箭头函数

    1
    2
    3
    4
    5
    6
    7
    List 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
    14
    List 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
    14
    bool 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
    4
    var printNum=(){        //这是一个匿名方法被赋值给了printNum
    print(123);
    };
    printNum(); //调用printNum方法可以 输出: 123

    例2:匿名方法的传参

    1
    2
    3
    4
    var 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
    10
    var 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
    10
    var 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
    10
    var 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
    10
    main() {
    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
    13
    main() {
    fn(){
    var a=1;
    return(){
    a++;
    print(a);
    };
    }
    var b=fn();
    b(); //输出: 2
    b(); //输出: 3
    b(); //输出: 4
    }
-------------本文有底学海无涯-------------