Dart 继承模型:单继承、多 mixin。
带条件地访问成员变量
// p 为 null 时 a 为 null;否则 a 为 p.y
var a = p?.y;
构建函数
两种构建函数:
class Point {
double x;
double y;
// this.x 是语法糖
// 构建函数的函数体为空时,花括号 {} 也可以不写
Point(this.x, this.y);
Point.fromJson(Map<String, double> json)
: x = json['x'],
y = json['y'];
}
void main() {
var p1 = Point(1, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
assert(p1.x == p2.x);
}
默认构建函数
如果你没有定义 constructor,Dart 会默认有一个 constructor,它不接受参数,不做任何事情;如果你定义了 constructor,不管它是带参数还是不带参数,默认的 constructor 都不会再生效。
如果子类没有定义 constructor,Dart 会默认有一个 constructor,它会调用父类的 no-arg constructor,再调用子类的。顺序如下:
- 对类中带默认值的 property 求值
- 对 initializer list 求值
- 调用父类的 no-arg constructor
- 调用子类的 no-arg constructor
写法例子:
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');
}
}
initializer list 的 N 种写法
Point.fromJson(Map<String, double> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
class Employee extends Person {
Employee() : super.fromJson(defaultData);
// ···
}
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
设置 final
的 pattern:
import 'dart:math';
class Point {
final num x;
final num y;
final num distanceFromOrigin;
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}
重定向到别的构建函数:
class Point {
double x, y;
// The main constructor for this class.
Point(this.x, this.y);
// Delegates to the main constructor.
Point.alongXAxis(double x) : this(x, 0);
}
Factory constructors
有些情况下,我们希望构建函数执行时:
- 不一定要构建新的对象,比如在缓存中取已有的对象
- 返回一个子类的对象
此时可以用 factory
关键字:
class Logger {
final String name;
bool mute = false;
// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
factory Logger.fromJson(Map<String, Object> json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
操作符重载
Dart 提供了一种很像 C++ 的操作符重载能力:
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown.
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
Getters and setters
Getter 和 setter 是把对属性的读写变成(不带参数的)函数:
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// Define two calculated properties: right and bottom.
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
抽象类
// This class is declared abstract and thus
// can't be instantiated.
abstract class AbstractContainer {
// Define constructors, fields, methods...
void updateChildren(); // Abstract method. (methods that has no implementation)
}
隐式接口
Dart 没有专门的接口结构(比如 Java 的 Interface)。它通过类和其属性的访问限制,隐式地定义了接口。
// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(String who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Impostor implements Person {
get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
mixins
mixin 是一种避免了多继承、但又可以共享一部分代码的机制:
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
你也可以用 class
关键词取代 mixin
,但用 mixin
关键词时,Musical
是无法被实例化的。
在类声明中 with Musical
的类,可以用 mixin
中的代码,而不需要继承它:
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
另外,如果 Musical
中的 entertainMe()
是抽象函数(没有实现),with Musical
的类都需要实现这个函数。类似的,canPlayPiano
这几个值,如果没有默认值,with Musical
的类都需要给它设置 getter / setter / override(?)。
类静态方法
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}
可调用的类
通过在类中实现一个 call
方法,使它的实例可以像函数一样被调用:
class WannabeFunction {
String call(String a, String b, String c) => '$a $b $c!';
}
var wf = WannabeFunction();
var out = wf('Hi', 'there,', 'gang');
main() => print(out);