前言
Dart是一个真正的面向对象语言,方法也是对象并且具有一种类型Function
。 这意味着,方法可以赋值给变量,也可以当做其他方法的参数。 也可以把Dart类的实例当做方法来调用。大家可以通过阅读lambda表达式与Kotlin高阶函数与Kotlin
中的函数类似对比学习。首先通过hello world了解一下Dart中的函数:
_printHello("白瑞德");
void _printHello(String name) {
print("hello: ${name}");
}
>>> hello: 白瑞德
注意:Dart没有public、protected、private的概念。但是如果变量或函数以下划线_
开始,则该函数或变量属于这个包私有(private)的方法。
函数的定义
函数定义指定特定任务的执行方式。在使用函数之前,必须先定义它。dart中函数的定义和Java中的类似。由函数入参、返回结果类型和函数体组成
String function_name(String parma) {
//statements
}
void function_name(String parma) {
//statements
}
function_name(parma) {
//statements
return 2;
}
其中void
关键字表示该函数不向滴啊用这返回任何值,可以省略不写。函数的入参也可以忽略参数类型,这样函数默认接受dynamic
类型的参数,也就是任何类型都可以传递。当省略了返回值类型的时候,也会默认返回值的类型为dynamic
。
注意:dynamic
类型可能会带来运行时异常:
_printInt(int name) {
return "Hello";
}
_printInt(_printInt(2))
这段代码会报:type 'String' is not a subtype of type 'int'
。
注意:上述三个function_name
是不可以出现在同一个代码块里,有Java开发经验的一定知道这种形式就是Java函数的重载,但这在Dart里是行不通的,Dart里有其他方式实现这种重载。
对于只有一个表达式的方法,可以选择使用缩写语法来定义:
String function_name(name) => name+name;
函数体只能是一个表达式,不能使用语句(if-else)
可选参数
Dart中没有类似Java重载的函那样的函数,我们可以使用可选参数来实现类似的功能。
可选参数可以是命名参数或者基于位置的参数,但是这两种参数不能同时当做可选参数。
可选命名参数
调用方法的时候,你可以使用这种形式paramName: value来指定命名参数。一个函数可以同时拥有可选参数和必选参数,但是必选参数必须在最前面
例如:
_printInt(age: 19,address: "粤海街道");
_printHello("白瑞德",age: 19);
_printInt({int age,String address}) {
...
}
_printHello(name,{int age,String address}) {
...
}
在可选参数的时候,可以使用=
来定义可选参数的默认值。默认值只能是编译时常量。如果没有提供默认值,则默认值为null。
//年龄默认为7,而address默认为null
_printHello(name,{int age = 7,String address}) {
...
}
可选位置参数
把一些方法的参数放到[]中就变成可选位置参数了:
_printString("白瑞德");
_printString([String name,int age = 7,String address]){
...
}
可选的命名参数的声明使用“{}”,使用“:”指定默认值,可选的位置函数的声明使用“[]”,使用“=”指定默认值。
重载与构造方法
Dart语言是同名函数的,即使入参不同。那么问题就来了,构造函数怎么办?难道只能一个构造函数吗?答案是否定的。
Dare支持命名构造函数,使用命名构造函数可以为一个类实现多个构造函数, 或者使用命名构造函数来更清晰的表明你的意图:
class User {
String name;
User.init();
User.initName(name){
this.name = name;
}
}
注意:构造函数不能继承,所以超类的命名构造函数 也不会被继承。如果你希望 子类也有超类一样的命名构造函数, 你必须在子类中自己实现该构造函数。
默认情况下,子类的构造函数会自动调用超类的无名无参数的默认构造函数。 超类的构造函数在子类构造函数体开始执行的位置调用。如果提供了一个 initializer list(初始化参数列表),则初始化参数列表在超类构造函数执行之前执行。 下面是构造函数执行顺序:
- initializer list(初始化参数列表)
- superclass’s no-arg constructor(超类的无名构造函数)
- main class’s no-arg constructor(主类的无名构造函数)
如果超类没有无名无参数构造函数,则你需要手工的调用超类的其他构造函数。在构造函数参数后使用冒号 (:) 可以调用 超类构造函数。
由于超类构造函数的参数在构造函数执行之前执行,所以参数可以是一个表达式或者一个方法调用:
class Student extends User{
Student.init() : super.init();
Student.initName(name):super.initName(name){
}
}
一等方法对象
在Dart中,有一种函数被称为:Functions as first-class objects
一等方法对象。可一把方法当做参数调用另外一个方法,也可以把方法赋值给一个变量。
printElement(element) {
print(element);
}
var list = [1, 2, 3];
list.forEach(printElement);
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
lambda/匿名函数/闭包
大部分方法都带有名字。也可以创建没有名字的方法,称之为匿名方法,有时候也被称为Lambda或者闭包,这是一种表示函数的简介方式。可以把匿名方法赋值给一个变量。
var printName =(num){
print(num);
return num;
};
//当只有一行表达式时,可以使用箭头函数
var printName =(num) => print(num);
一个闭包是一个方法对象,不管该对象在何处被调用,该对象都可以访问其作用域内的变量。方法可以封闭定义到其作用域内的变量。下面的示例中,makeAdder()捕获到了变量addBy。不管你在那里执行makeAdder() 所返回的函数,都可以使用addBy参数。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
main() {
// Create a function that adds 2.
var add2 = makeAdder(2);
// Create a function that adds 4.
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
结语
Dart中的函数使用基本讲解完毕了,想要进一步了解的可以去官方教程上学习