Dart 点将台 | extension 拓展方法

1. Dart 的拓展方法介绍

如果我们需要判断该字符串 是否是手机号 ,需要写个 正则 来校验,如果用的地方很多,每个地方都要些校验逻辑,或者抽离一个工具类辅助校验。但也没有想过可以直接使用   字符串.isPhone() 来校验?在 Dart 2.7,添加了 拓展方法 的特性,这使我们在 不修改 已有源码的基础上,可以方便地拓展 已有类型 的方法。代码如下:

main(){
  String number = "18715079389";
  print(number.isPhone()); // true

  String number2 = "28715079389";
  print(number2.isPhone()); // false
}

extension JudgeString on String {
  bool isPhone(){
    return RegExp(r'^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$').hasMatch(this);
  }
}

拓展方法的语法如下,关键字为 extensionon ,其中 名称 任意,类型就是待拓展类。 {} 内可以包含若干个方法体。

2. 拓展方法中的 this

拓展方法中可以使用 this 对象,那么这个 this 对象是什么呢?第一感觉,应该指的是调用这个方法的对象。下面通过一个小案例测试一下是不是这样的。如下,对 List 类进行拓展,有一个 check 方法,需要一个 List 入参,这样我们可以比较 入参this 的内存地址是不是同一个,使用 identical 方法进行比较。结果是 true 。这就说明:

拓展方法中的 this 确实指代的是 方法的调用者

main() {
  List<int> list = [0123];
  list.check(list);
}

extension ListPrint on List {
  void check(List list) {
    print(identical(list, this)); // true 
  }
}

另外也可以进行 运算符重载 的拓展。比如   DateTime 类中只是使用 add 方法进行加法计算。可以通过 extension 对原有的 DateTime 类进行运算符拓展。代码如下:

main() {
  final DateTime birthday = DateTime(19943281428);
  // 1994-07-06 16:30:00.000
  print(birthday + Duration(days: 100, hours: 2, minutes: 2));
}

extension DateTimeExt on DateTime {
  DateTime operator +(Duration other) => this.add(other);
}

3.拓展方法的注意点

拓展方法只能由对象调用,其名称 不可以 实例化使用。

拓展方法中 不可以 声明普通成员变量。

那你也许会有疑问,拓展名不能用,那他存在的价值是什么?拓展方法中虽然不能定义普通成员变量,但是可以定义 静态成员 。通过 名称.静态成员 可以访问。

那能拓展 静态方法 吗?  其实我们可以反过来想一想,拓展方法需要对象调用。静态方法是在实例化之前就已确定的,所以 this 是不可能在 static 方法中使用的。

这时可能有小机灵鬼会说,不用 this 不就行了吗?那不用 this ,拓展方法的意义何在?如下,在 ListPrint 中定义的静态方法,只能通过 ListPrint 调用,不能通过 List 调用。所以静态相关的和待拓展类并没有关系,是属于自己的行为。

4.拓展方法的优缺点

拓展方法的好处在使用起来非常方便,语义性也很强,复用性也很好,还能装逼于无形。

是药三分毒 ,如果名字没起好,或说拓展的方法非常杂乱,那在别人眼中,阅读你的代码将会非常吃力。或者会让别人疑惑: 为什么我的类里没有这个方法,难道我的版本太低了? 这样,对于拓展方法而言,就会出现一些混乱,这也是 使用者观看者 的信息不对等,而出现的理解性偏差。

其实这和贫富差距一样,是很难避免的,也并没有什么好的解决方案。在写拓展方法时注意命名的合理,多写注释,多写注释,多写注释,这样可以让 信息尽可能多的对等 ,毕竟你的脑子里想什么,别人很难捉摸出来。

其次就是规范性,如果拓展方法可以有一个 标识来区分 ,这样就能让信息拥有 辨识性 。比如,拓展方法的末尾都加 $ 字符。如果这成为了一种拓展规范,这样当读码的人看到,就可以迅速意识到这个方法是 拓展的 ,从而减少不必要的疑虑。

另外, 写码者 ,可以通过 $ 来触发提示,获取自己拓展的方法,能更快找到。

这里只是我的一个小想法,至于为什么是 $$ 为什么在末尾,其实并不重要,重要的是规范性的普及。就像章北海的最后一句话: 没关系的,都一样 。关于 Dart 的拓展方法也说得差不多了,本文就到这里,谢谢观看 ~