扩展方法
想给一个三方的libray添加一些新功能,比如像下面这样,将一个字符串转换为整数:
"1".toInt()
但 String 类中并没有 toInt() 这个方法,而且String类位于Dart核心库中,我们不可能对它进行修改进而添加新方法。这便是扩展方法(extension methods,简称扩展)的用武之地。
声明扩展
使用 extension ... on ... 语法声明一个扩展。
// ex551.dart
extension NumParse on String {
int toInt({int? radix}) => int.parse(this, radix: radix);
double toDouble() => double.parse(this);
}
void main() {
assert(10 == "10".toInt());
assert(1.1 == "1.1".toDouble());
}
这里的NumParse为扩展名,如果NumParse只是在定义它的library中使用,该名称可以省略。
extension on String {
// ... (omitted for brevity)
}
使用扩展方法
NumParse为String添加了两个扩展方法 toInt() 和 toDouble(),就像String自身定义的其它方法一样,直接调用它们即可。
// ex552.dart
import 'ex551.dart';
void main() {
assert(10 == "a".toInt(radix: 16));
}
假设另一个String的扩展 NumParse2,它定义的方法与NumParse存在冲突:
// ex551a.dart
extension NumParse2 on String {
int toInt() => int.parse(this);
double toDouble() => double.parse(this);
num toNum() => contains('.') ? toDouble() : toInt();
}
但你的程序又要同时倒入它们所在的library,怎么办?下面介绍避免此类冲突的两种方法。
方法1:使用show/hide限制暴露的API
// ex553.dart
import 'ex551.dart';
import 'ex551a.dart' hide NumParse2;
void main() {
print('abc'.toInt(radix: 16)); // Output: 2748
}
方法2: 将扩展看做包装类
// ex554.dart
import 'ex551.dart';
import 'ex551a.dart';
void main() {
print(NumParse("123").toInt()); // 1 Output: 123
print(NumParse2("456").toDouble()); // 2 Output: 456.0
print("789".toNum()); // 3 Output: 789
}
- 显示地调用
NumParse的toInt()方法,NumParse("123")看起来就像调用了一个构造函数,而NumParse就像一个包装类; - 这行代码与上一行类似;
toNum()方法只在NumParse2扩展中被定义了,因此直接调用也不会产生歧义。
如果两个扩展的名称相同,就可能要使用 前缀导入,即给导入的libray取一别名。
// ex555.dart
import 'ex551.dart' as lib1;
import 'ex551b.dart' as lib2;
void main() {
print(lib1.NumParse('def').toInt(radix: 16)); // Output: 3567
print(lib2.NumParse('234').toDouble()); // Output: 234.0
print("345".toNum()); // Output: 345
}