Dart的一些基础知识可以看Dart中文网,网上也有很多入门教程。这个系列只是我在学习过程很有用,但一些基础教程中未提及的。
Dart和Java在很多方面很相似,但也有很多不一样的地方,比如:
可选命名参数
调用方法的时候,你可以使用这种形式paramName: value
来指定命名参数。例如: enableFlags(bold: true, hidden: false);
在定义方法的时候,使用 {param1, param2, …}
的形式来指定命名参数:
/// Sets the [bold] and [hidden] flags to the values
/// you specify.
enableFlags({bool bold, bool hidden}) {
// ...
}
可选命名参数常用于类的构造函数,看参看类-构造函数可选命名参数
可选位置参数
把一些方法的参数放到[]
中就变成可选 位置参数了: 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');
Dart中类的定义、继承、重载和Java差不多,如果你会Java那Dart的面向对象也就很简单。但还是存在一些差异性的地方
例如:实列化的时一般是new Point();,Dart中new是可选的,Java是必须的。
常见的构造函数定义和Java一样,定义一个和类名字一样的方法就定义了一个构造函数,还可以带有其他可选的标识符:
class Point {
num x;
num y;
Point(num x, num y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
}
由于把构造函数参数赋值给实例变量的场景太常见了, Dart 提供了一个语法糖来简化这个操作:
class Point {
num x;
num y;
// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}
在看Flutter一些控件的源码时,经常能看到以下代码
const Text(this.data, {
Key key,
this.style,
this.strutStyle,
this.textAlign,
this.textDirection,
this.locale,
this.softWrap,
this.overflow,
this.textScaleFactor,
this.maxLines,
this.semanticsLabel,
}) : assert(data != null),
textSpan = null,
super(key: key);
构造函数也是函数,所以同样适用函数的可选命名参数,在加上Dart 提供了一个语法糖,所以可像以下代码调用
new Text('红色+黑色删除线+25号',
style: TextStyle(
color: const Color(0xffff0000),
),
)
在构造函数体执行可以初始化实例参数, 使用逗号分隔初始化表达式。
class Point {
num x;
num y;
Point(this.x, this.y);
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map jsonMap)
: x = jsonMap['x'],
y = jsonMap['y'] {
print('In Point.fromJson(): ($x, $y)');
}
}
警告: 初始化表达式等号右边的部分不能访问 this
。
初始化列表非常适合用来设置 final 变量的值。
有时候一个构造函数会调动类中的其他构造函数。 一个重定向构造函数是没有代码的,在构造函数声明后,使用 冒号调用其他构造函数。
class Point {
num x;
num y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}
默认情况下,子类的构造函数会自动调用超类的 无名无参数的默认构造函数。 超类的构造函数在子类构造函数体开始执行的位置调用。 如果提供了一个 initializer list(初始化参数列表) ,则初始化参数列表在超类构造函数执行之前执行。
如果超类没有无名无参数构造函数, 则你需要手工的调用超类的其他构造函数。 在构造函数参数后使用冒号 (:
) 可以调用 超类构造函数。
class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person {
// Person does not have a default constructor;
// you must call super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}
main() {
var emp = new Employee.fromJson({});
// Prints:
// in Person
// in Employee
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
(emp as Person).firstName = 'Bob';
}
下面是构造函数执行顺序: