### 异常(Exceptions)
1. ***throw***
* 抛出固定类型的异常
~~~
throw new FormatException('Expected at least 1 section');
~~~
* 抛出任意类型的异常
~~~
throw 'Out of llamas!';
~~~
* 因为抛出异常属于表达式,可以将throw语句放在=>语句中,或者其它可以出现表达式的地方
~~~
distanceTo(Point other) =>
throw new UnimplementedError();
~~~
2. ***catch***
* 将可能出现异常的代码放置到try语句中,可以通过 on语句来指定需要捕获的异常类型,使用catch来处理异常。
~~~
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
~~~
3. ***rethrow***
* rethrow语句用来处理一个异常,同时希望这个异常能够被其它调用的部分使用。
~~~
final foo = '';
void misbehave() {
try {
foo = "1";
} catch (e) {
print('2');
rethrow;// 如果不重新抛出异常,main函数中的catch语句执行不到
}
}
void main() {
try {
misbehave();
} catch (e) {
print('3');
}
}
~~~
4. ***finally***
* Dart的finally用来执行那些无论异常是否发生都执行的操作。
~~~
final foo = '';
void misbehave() {
try {
foo = "1";
} catch (e) {
print('2');
}
}
void main() {
try {
misbehave();
} catch (e) {
print('3');
} finally {
print('4'); // 即使没有rethrow最终都会执行到
}
}
~~~
### 函数 Function
* 以下是一个实现函数的例子:
~~~
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
~~~
1. ***main()函数***
* 每个应用程序都必须有一个顶层main()函数,它可以作为应用程序的入口点。该main()函数返回void并具有List参数的可选参数。
~~~
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
~~~
* 级联符号..允许您在同一个对象上进行一系列操作。除了函数调用之外,还可以访问同一对象上的字段。这通常会为您节省创建临时变量的步骤,并允许您编写更流畅的代码。
~~~
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
~~~
* 上述例子相对于:
~~~
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
~~~
* 级联符号也可以嵌套使用。 例如:
~~~
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
~~~
* 当返回值是void时不能构建级联。 例如,以下代码失败:
~~~
var sb = StringBuffer();
sb.write('foo') // 返回void
..write('bar'); // 这里会报错
~~~
* ***注意: 严格地说,级联的..符号不是操作符。它只是Dart语法的一部分。***
2. ***可选参数***
* 可选的命名参数, 定义函数时,使用{param1, param2, …},用于指定命名参数。例如:
~~~
//设置[bold]和[hidden]标志
void enableFlags({bool bold, bool hidden}) {
// ...
}
enableFlags(bold: true, hidden: false);
~~~
* 可选的位置参数,用\[\]它们标记为可选的位置参数:
~~~
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
~~~
* 下面是一个不带可选参数调用这个函数的例子:
~~~
say('Bob', 'Howdy'); //结果是: Bob says Howdy
~~~
* 下面是用第三个参数调用这个函数的例子:
~~~
say('Bob', 'Howdy', 'smoke signal'); //结果是:Bob says Howdy with a smoke signal
~~~
3. ***默认参数***
* 函数可以使用=为命名参数和位置参数定义默认值。默认值必须是编译时常量。如果没有提供默认值,则默认值为null。
* 下面是为命名参数设置默认值的示例:
~~~
// 设置 bold 和 hidden 标记的默认值都为false
void enableFlags2({bool bold = false, bool hidden = false}) {
// ...
}
// 调用的时候:bold will be true; hidden will be false.
enableFlags2(bold: true);
~~~
* 下一个示例显示如何为位置参数设置默认值:
~~~
String say(String from, String msg,
[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
//调用方式:
say('Bob', 'Howdy'); //结果为:Bob says Howdy with a carrier pigeon;
~~~
* 您还可以将list或map作为默认值传递。下面的示例定义一个函数doStuff(),该函数指定列表参数的默认list和gifts参数的默认map。
~~~
// 使用list 或者map设置默认值
void 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');
}
~~~
4. ***作为一个类对象的功能***
* 您可以将一个函数作为参数传递给另一个函数。
~~~
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 把 printElement函数作为一个参数传递进来
list.forEach(printElement);
~~~
* 您也可以将一个函数分配给一个变量。
~~~
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
~~~
5. ***匿名函数***
* 大多数函数都能被命名为匿名函数,如 main() 或 printElement()。您还可以创建一个名为匿名函数的无名函数,有时也可以创建lambda或闭包。您可以为变量分配一个匿名函数,例如,您可以从集合中添加或删除它。
* 一个匿名函数看起来类似于一个命名函数 - 0或更多的参数,在括号之间用逗号和可选类型标注分隔。
* 下面的代码块包含函数的主体:
~~~
([[Type] param1[, …]]) {
codeBlock;
};
~~~
* 下面的示例定义了一个具有无类型参数的匿名函数item,该函数被list中的每个item调用,输出一个字符串,该字符串包含指定索引处的值。
~~~
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
~~~
* 如果函数只包含一条语句,可以使用箭头符号=>来缩短它, 比如上面的例2可以简写成:
~~~
list.forEach((item) => print('${list.indexOf(item)}: $item'));
~~~
6. ***返回值***
* 所有函数都返回一个值,如果没有指定返回值,则语句return null,隐式地附加到函数体。
~~~
foo() {}
assert(foo() == null);
~~~