Flutter/Dart第19天:Dart高档特性之扩展办法(Extension methods)
Dart官方文档:https://dart.dev/language/extension-methods
重要说明:本博客依据Dart官网文档,但并不是简略的对官网进行翻译,在掩盖中心功用情况下,我会依据个人研制经历,参加自己的一些扩展问题和场景验证。
扩展办法概述
当咱们运用了一些被广泛运用的其他库或许自己的库时,咱们不太可能去修正这个库API,可是咱们又想给库添加一些办法,该怎么办?如:咱们想给String
类添加一些我自己常用的办法。
Dart作为一门集百家之长的编程言语,也考虑到了这个需求点,它供给了一个扩展办法(Extension methods)来处理问题问题。
如下代码样例,String
类型转化int
数字类型,惯例的做法如下:
int.parse('123');
那假如String
类型供给一个转为int
数字类型的办法,是不是更好:
'123'.parseInt()
想要完成上诉意图,经过扩展String
类型,供给对应办法即可:
import './19-ntopic-string-apis.dart';
void main() {
print('123'.parseInt());
// 成果:123
}
//
// 19-ntopic-string-apis.dart 内容
//
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
}
运用扩展办法
上一章节的最终,其实咱们现已展现了怎么界说和运用扩展办法。运用扩展办法,和运用类型的其他办法没有任何差异。
接下来咱们来看看,扩展办法在静态类型和动态类型的运用,和怎么处理同名扩展办法抵触。
静态类型和dynamic动态类型
特别注意:dynamic
动态类型制止运用扩展办法!如下代码样例,会抛出NoSuchMethodError
运行时反常。
import './19-ntopic-string-apis.dart';
void main() {
print('123'.parseInt());
// 成果:123
dynamic d = '2';
// NoSuchMethodError: Class 'String' has no instance method 'parseInt'.
print(d.parseInt());
}
可是扩展办法可用于类型推导上,如下代码无任何问题,因为变量v
的类型推导成String
类型:
import './19-ntopic-string-apis.dart';
void main() {
print('123'.parseInt());
// 成果:123
var v = '2';
print(v.parseInt());
// 成果:2
dynamic d = '2';
// NoSuchMethodError: Class 'String' has no instance method 'parseInt'.
print(d.parseInt());
}
dynamic
动态类型不行用户扩展办法的原因是,扩展办法只能接纳静态类型,因而调用扩展办法和调用静态办法相同高效。
扩展办法抵触
咱们在运用中,会引进多个库,假如有多个库都对同类型添加了同名的拓宽办法,那么就导出扩展办法抵触了。如:对String
类型,库A和库B都有pareInt()
扩展办法,那么这个扩展办法就存在抵触。
一般情况下,有3种办法来处理扩展办法的抵触:
榜首种办法,在引进库时,经过show
或许hide
关键字约束扩展办法:
// String扩展办法:parseInt()
import 'string_apis.dart';
// String扩展办法:parseInt(), `hide`躲藏扩展类型
import 'string_apis_2.dart' hide NumberParsing2;
// ···
// 运用了 'string_apis.dart' 中界说的扩展办法:parseInt()
print('42'.parseInt());
第二种办法,显现指定扩展类型的扩展办法:
// 扩展类型:NumberParsing,扩展办法:parseInt()
import 'string_apis.dart';
// 扩展类型:NumberParsing2,扩展办法:parseInt()
import 'string_apis_2.dart';
// 显现运用扩展类型
print(NumberParsing('42').parseInt());
print(NumberParsing2('42').parseInt());
第三种办法,假定第二种办法的扩展类型也相同,那么可在引进库添加前缀处理:
// 扩展类型:NumberParsing,扩展办法:parseInt()
import 'string_apis.dart';
// 扩展类型:NumberParsing,扩展办法:parseInt(),parseNum()
import 'string_apis_3.dart' as rad;
// 'string_apis.dart' 扩展办法:parseInt()
print(NumberParsing('42').parseInt());
// 'string_apis_3.dart' 扩展办法:parseInt()
print(rad.NumberParsing('42').parseInt());
// 'string_apis_3.dart' 扩展办法:parseNum()
print('42'.parseNum());
因为parseNum()
扩展办法不存在抵触,因而可直接运用。仅当存在扩展类型抵触时,才需求添加前缀。
完成扩展办法
在前面2个章节,其完成已提到了部分扩展办法的完成办法。扩展办法完成语法如下(扩展类型名是可选的):
extension <extension name>? on <type> {
(<member definition>)*
}
如下代码样例,对String
类型,添加了2个扩展办法(扩展类型名:NumberParsing
):
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
}
double parseDouble() {
return double.parse(this);
}
}
扩展类型中的成员,可所以办法、Getters、Setters和操作符,一起也可所以静态特点和静态办法,外围可通用一般类型静态特点和静态办法相同运用。
未命名的扩展类型
咱们界说未命名的扩展,它们的可见规模仅在库内容(类似于私有特点和办法);因为扩展类型未命名,因而无法清晰的用于抵触处理,它们的静态特点和静态办法,也只能在扩展内部运用:
extension on String {
bool get isBlank => trim().isEmpty;
}
完成泛型扩展
扩展也运用在泛型参数,如下代码样例,对List<T>
添加扩展办法和操作符,类型T在调用时才绑定静态类型:
extension MyFancyList<T> on List<T> {
int get doubleLength => length * 2;
List<T> operator -() => reversed.toList();
List<List<T>> split(int at) => [sublist(0, at), sublist(at)];
}
我的本博客原地址:https://ntopic.cn/p/2023110401