Dart2基础–函数
函数
Dart是一种完全面向对象的语言,所以函数也是对象并且有一个类型 Function.这意味着函数可以被赋值给一个变量或作为一个参数传递给另一个函数。你也可以像调用函数一样调用Dart类的实例。
下面的例子实现一个函数:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
虽然Effective Dart建议为公共API指明类型,但如果省略类型,函数仍然有效:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
对于只包含一个表达式的函数,可以使用简写语法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
=> expr语法是 =>{ return expr; }的简写。符号 => 也被称为箭头语法。
一个函数可以有两种类型的参数:必选参数和可选参数。首先列出必选参数,然后跟上可选参数。命名的可选参数也可以标记为 @required. 。
可选参数
可选参数可以是位置参数,也可以是命名参数,但是不能同时包含。
可选命名参数
当调用一个函数时,你可以指定命名参数: paramName:value ,例如:
enableFlags(bold: true, hidden: false);
当定义一个函数时,使用 {param1, param2, …} 来指定命名参数:
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}
你可以使用 @required 在任何Dart代码中注释命名参数,来指示它是必须参数。例如:
const Scrollbar({Key key, @required Widget child})
当构造一个 Scrollbar 时,分析器会在子参数不存在时报告问题。
Required 定义在 meta包中。要么直接导入包 package:meta/meta.dart,要么导入另一个已经包含 meta的包,例如Flutter中的 package:flutter/material.dart 。
可选位置参数
使用 [ ] 将函数的参数集合包裹起来将它们标记为可选位置参数。
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', 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;
}
assert(say('Bob', 'Howdy') ==
'Bob says Howdy with a carrier pigeon');
- 你也可以传递列表或者字典作为默认值。例如:
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()
任何一个app都必须有一个顶级main()函数,它作为app的入口。主函数 main() 返回 void 并且有一个List作为可选参数。
例如一个web应用的main()函数:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
函数对象
你可以将函数作为一个参数传递给另一个函数。例如:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// Pass printElement as a parameter.
list.forEach(printElement);
你也可以将一个函数指定给一个变量,例如:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
匿名函数
绝大多数函数都是命名函数,例如 main() 函数或 print() 函数。你也可以创建一个没有名字的函数,它被称为匿名函数,有时也叫做lambda表达式或者闭包(closure)。你也可以为变量指定匿名函数,也可以在集合中添加或删除它。
匿名函数看起来和命名函数很像:在括号中被逗号分隔的一个或多个参数,可选的类型注释等等。
下面的代码块包含函数的主体:
([[Type] param1[, …]]) {
codeBlock;
};
下面的示例定义了一个匿名函数,有一个无类型的参数 item 。列表里面的每一个项都会调用这个函数。
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
上面的函数只包含一个语句,可以使用箭头表示法来缩短它。
var list = ['apples', 'bananas', 'oranges'];
list.forEach(
(item) => print('${list.indexOf(item)}: $item'););
变量作用域(Lexical scope)
在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);
}
}
}
(Lexical closures)
闭包就是一个函数对象,它可以访问其词法范围中的变量,即使该功能在原始范围之外使用。
在下面的例子中, makeAdder() 捕获了变量 addBy ,无论返回的函数在哪里使用,它都会记住 addBy 。
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
return (num 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);
}
测试函数是否相等
以下是测试顶级函数,静态方法和实例方法是否相等的示例:
void foo() {} // A top-level function
class A {
static void bar() {} // A static method
void baz() {} // An instance method
}
void main() {
var x;
// Comparing top-level functions.
x = foo;
assert(foo == x);
// Comparing static methods.
x = A.bar;
assert(A.bar == x);
// Comparing instance methods.
var v = A(); // Instance #1 of A
var w = A(); // Instance #2 of A
var y = w;
x = w.baz;
// These closures refer to the same instance (#2),
// so they're equal.
assert(y.baz == x);
// These closures refer to different instances,
// so they're unequal.
assert(v.baz != w.baz);
}
返回值
所有的函数都有一个返回值。如果没有指定返回值,那么语句 return null; 会被隐式的添加在函数体的末尾。
foo() {}
assert(foo() == null);