函数

在Dart中,函数(或方法) 也是对象,它的类型是 Function。 这意味着,函数可以赋值给变量,也可以当做其他函数的参数。

定义函数

Dart中定义函数,基本上与Java类似

String greet(String name){
    return "hello,$name";
}

在Dart中,类型是可选,可以省略显式的类型,但仍然建议显式指定类型。

greet(name){
    return "hello,$name";
}

要注意,函数也是对象,所有函数都有返回值。当没有指定返回值的时候,函数会返回null。当然,如果你强行使用void来修饰函数,则函数真的没有返回值,这种情况就另当别论了。

函数的参数

Dart中支持两种可选参数

  • 命名可选参数
  • 位置可选参数

在Java中通常使用方法重载来实现同名方法的不同参数调用,Dart中则可以通过可选参数来实现相同效果。

命名可选参数

先来看一下命名参数,它使用花括号来定义参数列表

// 定义一个函数,参数列表用花括号包裹
enableFlags({bool bold, bool hidden}) {
    // do something
}

// 调用方式,传参时使用"参数名:值"的形式
enableFlags(hidden:true,bold:false);

如果在定义函数时,给参数列表中的参数设置默认值,则该参数就是可选的,函数调用时可以忽略该参数,使用默认的值。

// 定义add函数
add({int x, int y=1, int z=0}){
    print(x + y + z;
}

// 调用
add(x:18);              // 19
add(x:18, y:2, z:10);   // 30

这里需要注意一下,SDK 1.21之前的版本中,命名参数不能使用=号来设置默认值,而SDK 1.21之后,只能使用=号来设置默认值。因此,请检查并升级SDK版本。

位置可选参数

位置可选参数使用中括号来定义参数列表,中括号中的参数是可选的

// 定义add函数
add(int x, [int y, int z]){
    int result = x;
    if (y !=  null){
        result = result + y;
    }

    if (z !=  null){
        result = result + z;
    }
    print(result);
}

// 调用
add(18);           // 18
add(18,12);        // 30
add(18, 12, 15);   // 45

位置可选参数设置默认值

// 定义add函数
add(int x, [int y=0, int z=0]){
    print(x +y+z);
}

最后需要注意一下命名可选参数位置可选参数的区别,前者中的参数与顺序无关,无需按顺序传参,且传参数时需使用冒号;后者与顺序相关,传参必须依照顺序。

匿名函数

大部分函数都有名字,但我们也可以创建没有名字的函数,称为匿名函数,也被称为lambda表达式或者闭包。

// 定义匿名函数,并将其赋值给一个变量func,注意,函数体最后的花括号处必须有分号结束。
var func = (x,y){
    return x + y;
};

print(func(10,11));    // 21

注意,匿名函数与普通函数基本相同,也有参数列表,函数体,只是省去了函数名而已。

箭头函数

Dart中的箭头函数与JavaScript中的基本相同。当函数体中只包含一个语句时,我们就可以使用=>箭头语法进行缩写。注意,箭头函数仅仅只是一个简洁表达的语法糖。

普通函数

add(num x, num y){
    return x + y;
}

print(add(18,12));    // 30

箭头函数

// 与上面的普通函数完全等价
add(num x, num y) => x + y;

print(add(18,12));    // 30

箭头函数省略了花括号的表达,箭头后面跟一个表达式,函数的返回值也就是这个表达式的值。另外,箭头函数也可以与匿名函数结合,形成匿名箭头函数。

var func = (num x, num y) => x + y;

函数类型与函数签名

void func(Function f,String content){
  // 调用f函数
  f(content);
}

void main() {
  // 函数本身也是一种类型,可使用Function声明函数类型变量
  Function f = (String text){
    print(text);
  };

  // 将函数作为参数传递
  func(f, "编程之路");
}

如上例,我们可以声明函数类型变量,并将函数作为参数传递,但很快我们就会发现这样使用的弊端

void main() {
  // 当我们传入一个与参数不匹配的函数时,语法检查不会报错,但运行时会报错
  func((int a,int b){
    return a+b;
  }, "编程之路");
}

直接使用Function类型来声明函数变量做形式参数,是无法检查该函数的形式参数的,而且这样代码可读性太差,我们无法获知该函数变量的形式参数声明信息。这时候,就需要使用关键字typedef来定义函数的签名。

// 定义一个函数签名:表示F函数的原型为 void F(String)
// 其中F表示该函数类型的别名
typedef void F(String);

// 使用F类型来声明形参 f
void func(F f,String content){
  f(content);
}

void main() {
  // 此时再传入一个签名不匹配的函数,语法检查直接报错
  func((int a,int b){
    return a+b;
  }, 
}

使用typedef来定义函数的签名通常有两种写法,一种如上例,typedef后面直接跟函数的签名,另一种可读性更好,推荐使用

// 公式:typedef 函数类型别名 = 函数签名
typedef F = void Function(String);

公众号“编程之路从0到1”

20190301102949549

Copyright © Arcticfox 2020 all right reserved,powered by Gitbook文档修订于: 2024-06-09 20:22:55

results matching ""

    No results matching ""