愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

Dart学习笔记(二):方法

一、Dart方法

Dart中,方法也是对象并且是Function类的实例,因此,方法可以赋值给变量,也可以当做其他方法的参数,还可以是把Dart类的实例当做方法来调用,示例如:

String greet(String name) {
    return 'Hello, $name';
} 

对于公开的API,推荐使用静态类型,不过这不代表静态类型是强制的,也可以不适用静态类型,而使用自动类型推断:

greet(name) {
    return 'Hello, $name';
}

1、箭头语法

对于只有一个表达式的方法,还可以使用缩写的语法,如下:

bool greaterThanTen(n) => n > 10;
// 它相当于:
bool greaterThanTen(n) {
    return n > 10;
}

也就是说,缩写的语法=> expr相当于{ return expr; }

缩写语法中,不能使用语句ifelsewhile之类),但是可以使用表达式与条件表达式

2、必选参数与可选参数

方法的参数类型分为必选参数可选参数,必选参数必须在参数列表的最前面,而可选参数则需要放在必选参数的后面
1)命名参数
使用{ param1, param2, ... }来指定命名参数:

void greet({ String action, String what }) {
    print('$action $what');
}
// 调用方法如下:
greet(what: 'Hello', action: 'say');

2)可选参数
可选参数需要将放置于[]中,如下:

void greet(String from, String msg, [String device]) {
    print('$from says $msg');
    if (device != null) {
        print('via $device');
    }
}
// 调用方法如下:
greet('Ruphi', 'hello'); // 输出: Ruphi says Hello
greet('Ruphi', 'hello', 'iPhone 8 Plus');
/*
输出:
Ruphi says Hello
via iPhone 8 Plus
*/

3)默认参数
定义方法时,可以用=来指定参数的默认值,但是默认值只能是编译时常量,如果没有提供默认值,则默认值为null,如:

void greet({ String from = '?', String msg = 'Hello' }) {
    print('$from says $msg');
}
greet();

而对于位置参数(相对于命名参数)而言,则需要这么设置默认值:

void greet(String from, String msg, [String device = 'iPhone']) {
    print('$from says $msg');
    if (device != null) {
        print('via $device');
    }
}
greet('Ruphi', 'Hello');

3、函数入口

每个应用都要一个顶级的main()入口才能得到执行,main()的返回值是void,并且有个可选的List<String>参数(它提供看来自控制台的输入,可以使用args library来定义和解析命令行输入的参数数据):

void main(List<String> arguments) {
    print(arguments);
}

4、一等方法对象

可以将方法当做参数传递给另外一个方法,如:

printElement(element) {
    print(element);
}
var list = [1, 2, 3];
list.forEach(printElement);

方法也可以赋值给一个变量,如:

var showList = (list) => list.forEach((i) => print(i));

5、匿名方法

没有方法名的方法称为匿名方法(又称为lambda或者closure),匿名方法的语法如下:

([[Type] param1[, ...]]) {
    codeBlock;
};

示例:

var list = ['apple', 'orange', 'grape', 'banana'];
list.forEach((item) {
    print(list.indexOf(item).toString() + ': ' + item);
});

如果只包含一个语句,则可以使用=>语法,如以上可以改为:

list.forEach((item) => print(list.indexOf(item).toString() + ': ' + item));

6、词法作用域(静态作用域)

Dart变量的作用域在写代码的时候就已经确定了,因此,大括号里定义的变量就只能在大括号里访问,如:

var topLevel = true;
main() {
    var insideMain = true;
    myFunction() {
        var insideFunction = true;
        nestedFunction() {
            var insideNestedFunction = true;
        }
    }
}

7、词法闭包

一个闭包是一个方法对象,不论该对象在何处被调用,该对象都能访问自己作用域内的变量(即捕获了的变量),如下:

Function uid() {
    int id = 0;
    return () => id++; 
}
main() {
    var uidGenerator = uid();
    print(uidGenerator());
    print(uidGenerator());
    print(uidGenerator());
}
/*
输出:
0
1
2
*/

8、函数相等

判断函数相等的示例如下:

foo() {}               // 顶级函数

class A {
  static void bar() {} // 静态方法
  void baz() {}        // 实例方法
}

main() {
  var x;

  // 比较顶级方法
  x = foo;
  assert(foo == x); // 通过

  // 比较静态方法
  x = A.bar;
  assert(A.bar == x); // 通过

  // 比较实例方法
  var v = new A(); // A的实例 #1
  var w = new A(); // A的实例 #2
  var y = w;
  x = w.baz;

  // 因为 y.baz 和 x 都是指向实例#2的baz方法,因此它们是相等的
  assert(y.baz == x); // 通过

  // v.baz指向的是#1的baz方法,w.baz指向的是#2的baz方法,因此它们不相等
  assert(v.baz != w.baz); // 通过
}

9、返回值

所有的函数都返回一个值,如果没有指定返回值,则默认函数的最后一个语句是return null;,也就是说没有指定返回值的情况下,返回值是null