扩展类型
扩展类型(Extension types)是一种编译时抽象(仅存在编译时期),是对现有类型的一种静态包装。它们是静态 JS 互操作(static JS interop)的重要组件,因为它们可以轻松修改现有类型的接口,而无需产生包装类的成本。
扩展类型对底层类型(称为表示类型,representation type)对象可用的操作集(或接口)强制进行约束。定义扩展类型时,可以复用表示类型的某些成员、省略/替换其它成员、以及添加新功能,这有点类似于设计模式里的外观模式。
声明
使用 extension type 关键字声明扩展类型。
// ex561.dart
extension type IdNumber(int i) {} // 1
void main() {
var id = IdNumber(123); // 2
print(id); // 3 Output: 123
print(id.i); // 3a Output: 123
print(id.runtimeType); // 4 Output: int
}
- 声明扩展类型
IdNumber, 其表示类型为int,同时也隐式地定义了
- 构造函数
IdNumber(this.i), - 实例变量
final int i;
- 声明变量
id,赋值为IdNumber(123); - 分别打印
id和id.i; - 打印
id的运行时类型,结果为int,这印证了IdNumber在编译过程中被抹掉了。
构造函数
命名构造函数
除了隐式的构造函数外,还可以为扩展类型定义命名构造函数。
// ex562.dart
extension type IdNumber(int i) {
IdNumber.of(String str) : i = int.parse(str);
}
void main() {
var x = IdNumber(123);
var y = IdNumber.of('123');
assert(x == y);
}
采用命名构造函数的形式声明
使用命名构造函数的形式声明扩展类型时,可以灵活的定义不具名构函数(可选的)。
// ex563.dart
extension type IdNumber.of(int i) {
IdNumber(String str) : i = int.parse(str);
}
void main() {
var x = IdNumber.of(123);
var y = IdNumber('123');
assert(x == y);
}
对外隐藏不具名构造函数
// ex564.dart
extension type const IdNumber._(int i) {
const IdNumber.of(int i) : this._(i);
}
此例也演示了扩展类型如何声明 const 构造函数。
工厂构造函数
// ex565.dart
extension type IdNumber._(int i) {
factory IdNumber.of(int i) => IdNumber._(i);
}
成员
扩展类型不能定义 non-external 实例字段和抽象成员,除此之外可定义下列成员:
- 方法
- getter
- setter
- 操作符(operators)
// ex566.dart
extension type N(int i) {
N operator +(N m) => N(i + m.i);
int get n => i;
bool isPositive() => i > 0;
}
void main() {
var n = N(100);
print(n + N(23)); // Output: 123
print(n.n); // Output: 100
print(n.isPositive()); // Output: true
}
实现接口
扩展类型只可实现:
实现表示类型
一个扩展类型实现它的表示类型时,它便自动拥有了表示类型的所有的成员。
// ex567.dart
import 'package:meta/meta.dart';
extension type N(int i) implements int {
bool get isPositive => i > 0;
@redeclare
N operator +(int n) => N(i + n);
}
void main() {
var a = N(10);
var b = N(20);
var c = a + b;
print('${c.runtimeType} $c'); // Output: int 30
print('${a - b} ${a * b} ${a / b}'); // Output: -10 200 0.5
print('${a.isPositive} ${b.isNegative}'); // Output: true false
print(a + 1); // Output: 11
print(2 + a); // Output: 12
}
此例中扩展类型 N 是 类型 int 的透明包装,同时:
- 添加了新的 getter(
isPositive); - 重新定义了
+操作符。
注:meta package 中的注解@redeclare用于告诉编译器你有意地使用与超类相同的成员名称,如果事实并非如此,将收到一个警告。
实现表示类型的超类
// ex568.dart
extension type N(int i) implements num {} // 1
void main() {
var a = N(10);
var b = N(20);
var c = a + b; // 2
print('${c.runtimeType} $c'); // Output: int 30
print(1 & 2); // 3 Output: 0
print(a & b); // 3a
// Error:
// The operator '&' isn't defined for the type 'N'.
// Try defining the operator '&'.
}
- 扩展类型
N实现了类型num; num定义了+操作符,因此N也自然地拥有了+操作符;int定义了&操作符,因此1 & 2这样的表达式是有效的;
num和N都没有定义&操作符,因而a & b将引起编译错误。
实现基于同一表示类型的其它扩展类型
// ex569.dart
extension type A(num n) {
num get square => n * n; // 1
}
extension type B(num n) {
num get cube => n * n * n; // 2
}
extension type C(num n) implements A, B {} // 3
void main() {
var n = C(3);
print(n.runtimeType); // Output: int
print(n.square); // Output: 9
print(n.cube); // Output: 27
}
num的扩展类型A定义了一个 名为square的 getter;num的扩展类型B定义了一个 名为cube的 getter;num的扩展类型C同时实现了A和B,拥有了来自A的square和B的cube,这类似于多重继承。