Flutter 擴(kuò)展函數(shù)

Extension methods 就是我們常說(shuō)的擴(kuò)展函數(shù),像 Kotlin 等語(yǔ)言也有 擴(kuò)展函數(shù) 的特性,因此如果你了解其他語(yǔ)言的擴(kuò)展函數(shù),Dart 中的擴(kuò)展函數(shù)與其他語(yǔ)言基本一致。
擴(kuò)展函數(shù)最低版本要求:
environment:
sdk: ">=2.7.0 <3.0.0"
注意:空安全的最低版本是 2.12.0。
基礎(chǔ)
那么什么是擴(kuò)展函數(shù)?
簡(jiǎn)單理解,擴(kuò)展函數(shù)就是在現(xiàn)有的庫(kù)或者類中擴(kuò)展一個(gè)函數(shù),比如,我們希望將一個(gè)整數(shù)字符串轉(zhuǎn)換為 int 類型整數(shù),正常情況下,實(shí)現(xiàn)如下:
int.parse('10');
但是此中寫法不是很美觀,比較美觀的寫法是這樣的:
'10'.toInt();
但是 String 類型并沒(méi)有 toInt 方法,這時(shí)擴(kuò)展函數(shù)就有了用武之地,我們給 String 擴(kuò)展一個(gè) toInt 方法:
extension StringExtension on String {
int toInt() {
return int.parse(this);
}
}
擴(kuò)展函數(shù)使用關(guān)鍵字 extension。 StringExtension:是擴(kuò)展函數(shù)的名稱。 on :關(guān)鍵字后接需要擴(kuò)展的類型。 大括號(hào) :內(nèi)部是擴(kuò)展的方法。
有人覺(jué)得這個(gè)例子并不能體現(xiàn) 擴(kuò)展函數(shù) 的強(qiáng)大之處,看下面這個(gè)例子,假設(shè)有一個(gè)第三方庫(kù)的類 Person:
class Person {
final String name;
Person(this.name);
}
有2個(gè)實(shí)例 person1 和 person2,我們希望這個(gè)2個(gè)實(shí)例相加,返回一個(gè) Person 對(duì)象且name 值為2個(gè)name的拼接,中間用 , 隔開(kāi),不使用擴(kuò)展函數(shù)實(shí)現(xiàn):
Person add(Person person1,Person person2){
return Person('${person1.name},${person2.name}');
}
下面使用擴(kuò)展函數(shù)實(shí)現(xiàn):
extension PersonExtension on Person {
Person operator +(Person person) {
return Person('${this.name},${person.name}');
}
}
使用:
Person person1 = Person('lao');
Person person2 = Person('meng');
Person p = add(person1, person2);
print('${p.name}');
Person p1 = person1 + person2;
print('${p1.name}');
輸出結(jié)果:
flutter: lao,meng
flutter: lao,meng
結(jié)果都是一樣的,都可以實(shí)現(xiàn)要求,但擴(kuò)展函數(shù)的可讀性更好。
注意:擴(kuò)展函數(shù)可以實(shí)現(xiàn)的功能,使用工具類(方法)同樣也可以實(shí)現(xiàn)。
var 和 dynamic
不能對(duì) dynamic 類型使用擴(kuò)展函數(shù),下面的用戶在運(yùn)行時(shí)出現(xiàn)異常:
dynamic a = '10';
a.toInt();
toInt 是 String 類型的擴(kuò)展函數(shù),運(yùn)行出現(xiàn)如下異常:

但是如下代碼是正確的:
var b = '10';
b.toInt();
因?yàn)?b 以及被推斷為 String 類型,所以可以使用擴(kuò)展函數(shù)。
通過(guò)上面的例子,我們已經(jīng)對(duì)擴(kuò)展函數(shù)有了一定的了解,擴(kuò)展函數(shù)除了可以擴(kuò)展方法外,還可以擴(kuò)展屬性、操作符。
class Person {
String name;
Person(this.name);
}
擴(kuò)展函數(shù):
extension PersonExtension on Person {
// 擴(kuò)展操作符 +
Person operator +(Person person) {
return Person('${this.name},${person.name}');
}
// 擴(kuò)展 getter 屬性
int get nameLength => this.name.length;
//已經(jīng)存在的方法不能擴(kuò)展
// String toString(){
// return 'name:${this.name},age:${this.age}';
// }
//擴(kuò)展 方法
String log() {
return 'name:${this.name}';
}
}
使用:
Person person = Person('flutter');
print('${person.nameLength}');
print('${person.log()}');
解決沖突
假設(shè)現(xiàn)在有2個(gè)擴(kuò)展函數(shù),分別在 string_extension.dart 和 string_extension_1.dart 文件中,string_extension.dart 代碼如下:
extension StringExtension on String {
int toInt() {
return int.parse(this);
}
}
string_extension_1.dart 代碼如下:
extension StringExtension1 on String {
int toInt() {
return int.parse(this);
}
double toDouble() {
return double.parse(this);
}
}
string_extension_1.dart 中的代碼比 string_extension.dart 多了一個(gè) toDouble 方法。
引入2個(gè)擴(kuò)展函數(shù)并使用 toInt 方法:
import 'string_extension.dart';
import 'string_extension1.dart';
String a = '10';
a.toInt();
此時(shí),無(wú)法編譯通過(guò),異常如下:

異常原因:2個(gè)擴(kuò)展函數(shù)中都有 toInt 方法。
解決方案1: 指定使用哪一個(gè)擴(kuò)展函數(shù)
String a = '10';
StringExtension(a).toInt();
解決方案2: 使用 hide 和 show 來(lái)限制
import 'string_extension.dart';
import 'string_extension1.dart' hide StringExtension1;
String a = '10';
a.toInt();

