定义
Dart是一种真正的面向对象语言,因此即使是函数也是对象并且具有类型Function
。这意味着函数可以分配给变量或作为参数传递给其他函数。也可以调用Dart类的实例,就像普通函数调用的方式一样。详情可参考 Callable classes。
定义函数:
// 最前面的bool表示函数返回bool值,参数atomicNumber前的int表示接收类型为int,{}内为函数体
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
// 推荐在任何时候都标注函数的返回类型,如果不标注函数依然可以执行
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
箭头函数
如果函数只包含一个表达式,可以简写成如下形式,=> 后面的表达式将作为函数的返回结果:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
只有表达式允许出现在箭头函数中,也就是说三元表达式可以用在箭头函数中,但是 if
等语句无法在箭头函数中使用。
参数
函数可以有两种类型的参数:必需参数(required)和可选参数(optional)。首先列出所需参数,然后列出可选参数。可选参数可以是命名的参数或占位参数。
命名参数
命名参数是可选参数的一种,非必填:
// 定义两个叫bold和hidden的参数
void enableFlags({bool bold, bool hidden}) {...}
// 执行时传入对应名称和值
enableFlags(bold: true, hidden: false);
尽管命名参数是一种可选参数,但可以使用@required
对它们进行标注,以表明该参数是必需的:
// 如果用户在传入参数时没有指定child,那么编译器将会发出一个问题。
const Scrollbar({Key key, @required Widget child})
使用@required
需要引入import package:meta/meta.dart
。
占位参数
占位参数也是可选参数的一种,通过[]
将它们标记为可选的占位参数:
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'
默认参数值:
函数可以使用=
来定义命名和占位参数的默认值。默认值必须是编译时常量。如果未提供默认值,则默认值为null
。
命名参数的默认值
// 定义bold和hidden的默认参数为false
void enableFlags({bool bold = false, bool hidden = false}) {...}
// 这里传入了bold的值为true,所以函数中bold为true,hidden为默认值false
enableFlags(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;
}
// 不传入占位参数, device等于默认值carrier pigeon
say('Bob', 'Howdy') // 'Bob says Howdy with a carrier pigeon');
前面的例子中都是字符串和bool等简单的类型,对于Maps
和List
占位参数和命名参数也是支持的:
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');
}
doStuff();
/// 结果如下,由于未传值,所以list和gifts都等于默认值。
/// list: [1, 2, 3]
/// gifts: {first: paper, second: cotton, third: leather}
main函数
每个应用程序都必须具有顶级main函数,该函数用作应用程序的入口点。main函数返回void,并为参数提供可选的List
参数。
webapp的main函数例子:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
..
级联操作符允许对一个对象进行连续操作,这里的text
和onClick
都是对querySelector('#sample_text_id')
进行的操作。
main函数还可以接收命令行参数来执行:
// 在命令行如下操作: dart args.dart 1 test
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
函数是一等公民
也就是说你可以把函数当做普通类型进行参数传递和赋值给变量:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 这里printElement作为参数传递给了forEach方法
list.forEach(printElement);
// 赋值方法给变量
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
匿名函数
大多数函数都是命名函数,例如main()
或printElement()
。但是也可以创建没有名字的匿名函数、lambda或闭包。或者为变量分配匿名函数,以便操作匿名函数。
var list = ['apples', 'bananas', 'oranges'];
// 这里的forEach接收了一个匿名函数,传入参数是list的每一项
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
// 结果
// 0: apples
// 1: bananas
// 2: oranges
// 因为这个匿名函数只有一个表达式所以可以简写成箭头函数
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
作用域
Dart是词法作用域的语言,也就是说变量的作用域是在定义的时候确定的,只需通过代码的布局。就可以可以“向外跟随花括号”以查看变量是否在当前作用域内:
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
// nestedFunction 可以访问所有这里定义变量
// myFunction 除了insideNestedFunction变量,其他都可以访问。
闭包
闭包是指一个函数可以访问其词法范围中的变量,即使该函数在其原始范围之外执行也是如此。
函数可以留存其作用域内定义的变量。在以下示例中,makeAdder()
中定义了变量addBy
。无论返回的函数在哪里,它都会记住addBy:
/// 这里定义了一个匿名函数,并作为结果返回,这个函数记住了变量addBy
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// add2 将会记住 2
var add2 = makeAdder(2);
// add4 将会记住 4
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
返回值
所有函数都返回一个值。如果未指定返回值,则该语句返回null, 隐式附加到函数体中:
foo() {}
assert(foo() == null);