前言
这篇文章记录了在探索Extension Methods的道路上遇到的坑与收获。查阅太多文章都是直接机翻的国外文章,好多坑点根本没有提到。希望这篇文章可以帮助到大家。
什么是Dart Extension Methods
Extension Methods 属于Dart高级用法。含义也非常容易理解,就是字面意思-拓展方法,用于给无法或不想直接修改的类或库拓展自己想要函数。熟悉移动端开发的小伙伴基本都可以轻车熟路,它与 iOS 的 Extension 和 Android 的 Extension Methods都是一样的。
环境配置
要想使用 Extension Methods的话,Flutter SDK版本最低要1.12.13,Dart SDK的版本必须高于2.7.0,在pubspec.yaml里配置:
environment:
sdk: ">=2.7.0 <3.0.0"
同时需要在pubspec.yaml同级创建analysis_options.yaml文件,里面配置:
analyzer:
enable-experiment:
- extension-methods
analysis_options.yaml还可以添加一些Dart其他用法,比如代码规范校验等,此次就不在这里做拓展。代码规范校验可以参看法老的Flutter Analysis Options。
用法
Extension Method的语法也非常简单,如下:
extension <extension_name> on <type> {
(<member_definition>)*
}
比如我想给String扩展一个打印自己的方法
extension StringExtension on String{
printMyself(){
print("printMyself---" + this);
}
}
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
widget.title.printMyself();
});
系统加载中。。。
应用场景
1.功能定制化
日常开发过程中总会遇到一些业务项比较定制化的需求,比如对金额做特定处理展示千位符或单位的,对时间做处理进行格式化的。Extension Methods就可以非常好的处理这些,并汇总在一起。
2.第三方库拓展
在没有遇到Extension Methods之前,我们想要对某个第三方类进行一些统一的配置预设值。大多数做法可能是跟我下面差不多,做一个包装类来进行操作:
class ZNHttpClient {
static Dio _dio;
//initDio
Future<Dio> getDio() async {
//Do Something
...
_dio.options.responseType = ResponseType.JSON;
return _dio;
}
}
现在直接在原库上进行拓展
extension DioExtension on Dio{
Future<Dio> getDio() async {
//Do Something
...
return dio;
}
}
注意事项
上面吹了Extension Methods 能在项目中帮我们优化代码的应用场景,这边就要把它从神坛上拉下来。
1.虽然Extension Methods可以对类进行扩展,但不是什么都可以扩展的,以下的情况就会让代码直接产出编译错误:
- 声明一个具有与扩展名相同的基本名称的成员。
- 声明与扩展名相同的类型参数。
- 声明一个具有与任何扩展程序类型参数名称相同的基本名称的成员。
- 声明两个具有相同基本名称的成员,除非一个成员是getter而另一个是setter。
- 声明一个具有相同名字的setter和getter,一个是静态的,另一个不是。
- 声明具有相同名字成员作为成员声明由Object(==,hashCode,toString,noSuchMethod,runtimeType)。这适用于静态和实例成员声明。
- 声明一个构造函数。
- 声明一个实例变量。
- 声明一个抽象成员。
- 声明成员,其正式参数标记为covariant。
2.Extension Methods写法如下,则只对当前文件有效:
extension _StringExtension on String{
printMyself(){
print("printMyself---" + this);
}
}
extension on String{
printMyself(){
print("printMyself---" + this);
}
}
因为上面两个声明都为私有声明。第一个很好理解,扩展名加了_;第二就很难理解了,我也在这个上面耗费了好长时间,最后在官方的文档找到下面短短的一句话。
To create a local extension that’s visible only in the library where it’s declared, either omit the extension name or give it a name that starts with an underscore (_).
下面这个解释我在什么地方见到的,但是后来找不到了。后续找到了或者有朋友找到的麻烦帮忙指正一下,感激不尽。
extension on String{
printMyself(){
print("printMyself---" + this);
}
}
等同于
extension _ on String{
printMyself(){
print("printMyself---" + this);
}
}
3.当因方法名冲突时,可以使用下面的形式进行调用:
- show & hide
// Defines the String extension method parseInt().
import 'string_apis.dart';
// Also defines parseInt(), but hiding NumberParsing2
// hides that extension method.
import 'string_apis_2.dart' hide NumberParsing2;
- 显式调用
extension StringExtension on String{
int get length {
print("length---" + this.length.toString());
return this.length;
}
printMyself(){
print("printMyself---" + this);
}
}
print(StringExtension(widget.title).length);
4.不能使用类型推断
这个我还没理解到位,可以参看参考链接 Dart Extension Methods Fundamentals里的It Is All Static段落。