1.函数
Dart 是一门真正面向对象的语言, 甚至其中的函数也是对象,并且有它的类型 Function
。 这也意味着函数可以被赋值给变量或者作为参数传递给其他函数。 也可以把 Dart 类的实例当做方法来调用。1
2
3int sum(num num1, num num2) {
return num1 + num2;
}
如果函数中只有一句表达式,可以使用简写语法:1
sum(num1, num2) => num1 + num2;
=> expr
语法是 { return expr; }
的简写。 => 符号 有时也被称为 箭头 语法。
提示: 在箭头 (=>) 和分号 (;) 之间只能使用一个 表达式 ,不能是 语句 。 例如:不能使用 if 语句 ,但是可以是用 条件表达式.
函数有两种参数类型: required 和 optional。 required 类型参数在参数最前面, 随后是 optional 类型参数。 命名的可选参数也可以标记为 “@ required”。
可选参数
可选参数可以是命名参数或者位置参数,但一个参数只能选择其中一种方式修饰。可选参数可以分为 命名可选参数
和 位置可选参数
定义方式:1
2命名可选参数: {param1, param2, ...}
位置可选参数: [param1, param2, ...]
命名可选参数
1 | // 命名可选参数 |
Flutter
创建实例的表达式可能很复杂, 因此窗口小部件构造函数仅使用命名参数。 这样创建实例的表达式更易于阅读。
使用 @required
注释表示参数是 required 性质的命名参数, 该方式可以在任何 Dart 代码中使用(不仅仅是Flutter)。1
const Scrollbar({Key key, Widget child})
Required 被定义在 meta package。 无论是直接引入(import) package:meta/meta.dart ,或者引入了其他 package,而这个 package 输出(export)了 meta,比如 Flutter 的 package:flutter/material.dart。
位置可选参数
将参数放到 [] 中来标记参数是可选的:1
2
3
4
5
6
7String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
默认参数值
在定义方法的时候,可以使用 = 来定义可选参数的默认值。 默认值只能是编译时常量。 如果没有提供默认值,则默认值为 null。
下面是设置可选参数默认值示例:1
2
3
4
5// 设置 [bold] 和 [hidden] 标志 ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold 值为 true; hidden 值为 false.
enableFlags(bold: true);
list 或 map 可以作为默认值传递。 下面的示例定义了一个方法 doStuff(), 并分别指定参数 list 和 gifts 的默认值。1
2
3
4
5
6
7
8
9
10void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
函数是一等对象
一个函数可以作为另一个函数的参数。同样可以将一个函数赋值给一个变量。1
2
3
4
5
6
7
8
9void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 将 printElement 函数作为参数传递。
list.forEach(printElement);
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
匿名函数
多数函数是有名字的, 比如 main() 和 printElement()。 也可以创建没有名字的函数,这种函数被称为 匿名函数, 有时候也被称为 lambda 或者 closure 。 匿名函数可以赋值到一个变量中, 举个例子,在一个集合中可以添加或者删除一个匿名函数。
匿名函数和命名函数看起来类似— 在括号之间可以定义一些参数或可选参数,参数使用逗号分割。1
2
3([[Type] param1[, …]]) {
codeBlock;
};
下面例子中定义了一个包含一个无类型参数 item 的匿名函数。 list 中的每个元素都会调用这个函数,打印元素位置和值的字符串。1
2
3
4var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
如果函数只有一条语句, 可以使用箭头简写。粘贴下面代码到 DartPad 中 并点击运行按钮,验证两个函数是等价性。1
2list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
闭包
闭包 即一个函数对象,即使函数对象的调用在它原始作用域之外, 依然能够访问在它词法作用域内的变量。
函数可以封闭定义到它作用域内的变量。 接下来的示例中, makeAdder() 捕获了变量 addBy。 无论在什么时候执行返回函数,函数都会使用捕获的 addBy 变量。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/// 返回一个函数,返回的函数参数与 [addBy] 相加。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// 创建一个加 2 的函数。
var add2 = makeAdder(2);
// 创建一个加 4 的函数。
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
闭包在 Dart 的 for 循环中会捕获循环的 index 索引值, 来避免 JavaScript 中常见的陷阱。 请思考示例代码:1
2
3
4
5var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
和期望一样,输出的是 0 和 1。 但是示例中的代码在 JavaScript 中会连续输出两个 2 。
2.switch和case
在 Dart 中 switch 语句使用 == 比较整数,字符串,或者编译时常量。 比较的对象必须都是同一个类的实例(并且不可以是子类), 类必须没有对 == 重写。 枚举类型 可以用于 switch 语句。
在 case 语句中,每个非空的 case 语句结尾需要跟一个 break 语句。 除 break 以外,还有可以使用 continue, throw,者 return。1
2
3
4
5
6
7
8
9
10var command = 'OPEN';
switch (command) {
case 'OPEN':
executeOpen();
// ERROR: 丢失 break
case 'CLOSED':
executeClosed();
break;
}
case 程序示例中缺省了 break 语句,导致错误。
但是, Dart 支持空 case 语句, 允许程序以 fall-through 的形式执行。1
2
3
4
5
6
7
8var command = 'CLOSED';
switch (command) {
case 'CLOSED': // Empty case falls through.
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
3.异常
Dart 代码可以抛出和捕获异常。 异常表示一些未知的错误情况。 如果异常没有被捕获, 则异常会抛出, 导致抛出异常的代码终止执行。
和 Java 有所不同, Dart 中的所有异常是非检查异常。 方法不会声明它们抛出的异常, 也不要求捕获任何异常。
Dart 提供了 Exception
和 Error
类型, 以及一些子类型。 当然也可以定义自己的异常类型。 但是,此外 Dart 程序可以抛出任何非 null 对象, 不仅限 Exception 和 Error 对象。
throw
下面是关于抛出或者 引发 异常的示例:1
throw FormatException('Expected at least 1 section');
也可以抛出任意的对象:(不建议)1
throw 'Out of llamas!';
catch
捕获异常可以避免异常继续传递(除非重新抛出( rethrow )异常)。 可以通过捕获异常的机会来处理该异常:1
2
3
4
5
6
7
8
9
10
11
12try {
breedMoreLlamas();
} on OutOfLlamasException {
// 一个特殊的异常
buyMoreLlamas();
} on Exception catch (e) {
// 其他任何异常
print('Unknown exception: $e');
} catch (e) {
// 没有指定的类型,处理所有异常
print('Something really unknown: $e');
}
捕获语句中可以同时使用 on
和 catch
,也可以单独分开使用。 使用 on 来指定异常类型, 使用 catch 来 捕获异常对象。
如果仅需要部分处理异常, 那么可以使用关键字 rethrow
将异常重新抛出。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}