Functions 函数
Dart是一种面向对象语言,所以即使函数也是对象,也有一个类型Function。这意味着函数可以分配给变量或作为参数传递给其他函数。我们还可以像调用函数一样调用Dart类的实例。
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
尽管Dart建议为公共API添加类型注释,但如果省略类型,该函数仍然有效:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
和JS类似,如果函数只有一个表达式,我们可以使用短语法箭头函数
。
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
Params 参数
函数可以具有任意数量的参数。这些参数后面可以是命名参数,也可以是可选的位置参数(但不能同时)。
一些API,尤其是Flutter小部件构造函数只使用具名参数
具名参数
定义函数是指定具体的参数,具名参数是可选的
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool? bold, bool? hidden}) {...}
调用函数时,可以使用paramName:value指定命名参数。例如:
enableFlags(bold: true, hidden: false);
虽然具名参数是可选的,我们可以用require
来指定这个参数是必须的:
const Scrollbar({super.key, required Widget child});
当我们将参数用[]
标记为可选参数:
String say(String from, String msg, [String? device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
然后调用时,可以不带上可选参数:
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
也可以带上可选参数:
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
参数默认值
我们可以使用=
来定义函数的默认值,默认值必须是编译时的常量,如果参数没有默认值,则默认为null
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold will be true; hidden will be false.
enableFlags(bold: true);
位置参数示例:
String say(String from, String msg, [String device = 'carrier pigeon']) {
var result = '$from says $msg with a $device';
return result;
}
assert(say('Bob', 'Howdy') == 'Bob says Howdy with a carrier pigeon');
当然,我们也可以指定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');
}
Main() 函数
所有的应用程序都必须有一个顶层函数main()
。
main()函数没有返回值,表示的是程序的开始。
void main() {
print('Hello, World!');
}
匿名函数
大多数函数都是具名的,例如main()或printElement()。我们也可以创建一个名为匿名函数的无名函数,有时也可以创建lambda或闭包。我们可以将匿名函数分配给变量,比如我们可以在集合中进行添加或删除操作。
匿名函数看起来类似于具名函数,括号之间用逗号和可选类型注释分隔零个或多个参数。
const list = ['apples', 'bananas', 'oranges'];
list.map((item) {
return item.toUpperCase();
}).forEach((item) {
print('$item: ${item.length}');
});
这里的:
(item) {
print('$item: ${item.length}');
}
就是匿名函数。
Lexical scope 词域
在JS中,我们通常称为作用域。
下面的例子可以简单看下,理解一下就行了。
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);
}
}
}
Lexical closures 闭包
闭包是一个函数对象,它可以访问其词法范围内的变量,即使函数在其原始范围外使用。
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(int addBy) {
return (int i) => addBy + i;
}
void 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);
}
makeAdder实际上返回了一个函数,所以变量add2包含的是一个函数的引用,然后才调用的add2,add4也一样。
Return Values 返回值
所有函数都返回一个值。如果未指定返回值,则语句返回null;隐式附加到函数体。
foo() {}
assert(foo() == null);