如果你查閱List類的API文檔耐量,你會看見類型的寫法是List<E>
這里的E就是范型昭雌,它指代這個類型的實(shí)例是某種類型相關(guān)的撞叽。
為什么使用范型蝇率?
范型通常用來保證類型安全,并且他還有更多的好處是你的代碼運(yùn)行:
- 正確指定泛型類型會產(chǎn)生更好的代碼峡扩。
- 您可以使用泛型來減少代碼重復(fù)踱蠢。
使用范型可以讓工具檢測出更多書寫錯誤:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error
另一個使用原因是可以減少代碼重復(fù)汁汗,比如你想實(shí)現(xiàn)一個對象緩存:
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
你會發(fā)現(xiàn)你經(jīng)常能用到字符串緩存撮抓,或者Int緩存妇斤,所以你又照著原有代碼定義了個StringCache或者IntCache之類的:
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
后來你又想定義各種類型的緩存,但建立那么多的類丹拯,還都是重復(fù)的站超。你自己都覺得煩。這時你需要用范型來處理這種問題:
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
這里T只是一個占位符咽笼,當(dāng)你真正聲明Cache對象的時候需要指明T所指代的類型顷编。
使用集合字面量
集合字面量期望你添加明確的范型:
var names = <String>['Seth', 'Kathy', 'Lars'];
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
使用范型構(gòu)造函數(shù)
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
var nameSet = Set<String>.from(names);
或者非命名構(gòu)造函數(shù):
var views = Map<int, View>();
范型集合和它們包含的類型
Dart中的范型是具體化的戚炫,這意味著你可以在運(yùn)行時獲取范型的類型剑刑,例如你可以測試集合的類型:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
注意這里和Java完全相反,Java的范型是可擦除的,你可以判斷這個類型是否是
List
施掏,而不能判斷這個類型是否是List<String>
范型限制
和Java類似钮惠,限制范型的范圍的方式可以使用extends
關(guān)鍵字:
class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}
class Extender extends SomeBaseClass {...}
這時你就只可以使用SomeBaseClass
類型或者它的子類當(dāng)作范型了:
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
這時你可以指定沒有范型的Foo
,它的范型默認(rèn)是SomeBaseClass
:
var foo = Foo();
print(foo); // Instance of 'Foo<SomeBaseClass>'
你不可以指定非SomeBaseClass
的子類七芭,下面的代碼不能通過編譯:
var foo = Foo<Object>();
使用范型方法
起初素挽,Dart的范型只能使用類級別的范型,后來可以在方法上定義方法級別的范型了狸驳。
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}
類似Java的范型方法预明,這里定義T時需要在方法名之后定義一個新的范型變量。它有三種用途:
- 當(dāng)作方法返回值
- 當(dāng)作參數(shù)
- 在方法內(nèi)部使用
更多信息參考使用范型方法