函数声明
dart是一个面向对象语言,所有的方法,都是Function的一个对象。下面是一个dart的函数声明:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
dart中也类似kotlin,可以自己推断函数类型,尽管这并不推荐:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
同样,也可以直接使用箭头形式:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
在dart中=> expr
语法是{ return expr; }
的简写,这和lambda一样,在dart中这称为箭头语法。
注意:dart中的箭头语法其实和java8的lambda很像,它没有kotlin那么灵活,它只能像java8一样指定一个表达式,而不能指定一个函数。
可选参数
可选参数可以是位置参数或者是命名参数,但是不能两者都是。
可选命名参数
当使用一个命名参数的时候就使用类似Objective-c的语法:
enableFlags(bold: true, hidden: false);
这个函数的定义就需要如下语法:
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}
命名参数如果是必须指定的那么就要添加@required
注解。例如:
const Scrollbar({Key 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');
参数默认值
类似kotlin或者php,dart的参数默认值也是等号定义,默认值要求是编译时常量。如果没有指定默认值,那么可选参数的默认值就是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');
因为list和map也可以声明为const的,所以它们可以作为默认值:
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()函数
和java类似,dart的主函数也是程序入口。dart的主函数不像c语言那样需要使用返回值来表示进程执行结果,所以返回值是void,并且有个可选参数类型为List<String>
用来指代程序执行参数,不过这个通常用不太到。
下面是一个简单的web程序:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
这里的
..
操作符是一种简化语法,在dart中称为及联(cascade)。他可以让你省去编写构建者模式冗杂语句的麻烦。
这是一个使用main函数的命令行app的写法:
// Run the app like this: 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');
}
你可以使用args库来定义和转换命令行参数。
函数用作first-class对象
你可以把一个函数当成一个参数传递给一个方法,例如:
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()
或者printElement()
。你可以定义一些匿名函数,有时候它们被称作lambda或者闭包。匿名函数可以使用一个变量声明。
一个匿名函数看起来和命名函数很相似,在一个圆括号中有一个或者多个参数,用逗号分隔,并且含有可选类型注解。
下面是dart的匿名函数定义范式,中括号表示可选。
([[Type] param1[, …]]) {
codeBlock;
};
下面就是一个匿名函数的例子:
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
在这里item是词法分析器由范型来确定类型的,这里被推测为字符串类型。当然也可以明确在item前面标识String类型。
上面例子中由于匿名函数内部只有一个语句,它可以被简写成如下形式,这和java8或者kotlin都是类似的:
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);
}
}
}
这里只是和java有点区别,java如果是外部变量想在匿名内部类中使用的话需要加上final修饰,进而成为一个常量。这里dart可以使用变量,应该是采用类似kotlin在编译器内部会多生成成一个常量引用用来存储变量内容的方式来使用变量(猜的)。不过这里其实无需求甚解。新的语言普遍都能在匿名函数中使用变量。
词法闭包
一个闭包可以访问它对应词法范围内的变量,即使这个函数已经在那个词法范围以外了。
下面是一个函数生成器的例子,无论这个函数在哪,他都会记住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);
}
这里主要体现了不同对象的成员函数是不同的函数对象。
返回值
所有方法都有返回值,如果没有返回值,那么这个方法会隐式的返回null:
foo() {}
assert(foo() == null);
网友评论