Dart彙總請點選這裡
泛型
泛型是任何強類型語言都擁有的一種機制,用<>來标注類型。
使用泛型有兩個優點:
- 必須指定資料的類型,類型安全,更易解讀;
- 避免代碼重複,使代碼更簡潔;
在 API 文檔中你會發現基礎數組類型 List 的實際類型是 List 。 <…> 符号将 List 标記為 泛型 (或 參數化) 類型。 這種類型具有形式化的參數。 通常情況下,使用一個字母來代表類型參數, 例如 E, T, S, K, 和 V 等。
為什麼使用泛型
在類型安全上通常需要泛型支援, 它的好處不僅僅是保證代碼的正常運作:
正确指定泛型類型可以提高代碼品質。
使用泛型可以減少重複的代碼。
如果想讓
List
僅僅支援字元串類型, 可以将其聲明為
List<String>
(讀作“字元串類型的 list ”)。 那麼,當一個非字元串被指派給了這個 list 時,開發工具就能夠檢測到這樣的做法可能存在錯誤。 例如:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // 錯誤
另外一個使用泛型的原因是減少重複的代碼。 泛型可以在多種類型之間定義同一個實作, 同時還可以繼續使用檢查模式和靜态分析工具提供的代碼分析功能。 例如,假設你建立了一個用于緩存對象的接口:
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
後來發現需要一個相同功能的字元串類型接口,是以又建立了另一個接口:
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
後來,又發現需要一個相同功能的數字類型接口 … 這裡你應該明白了。
泛型可以省去建立所有這些接口的麻煩。 通過建立一個帶有泛型參數的接口,來代替上述接口:
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
在上面的代碼中,T 是一個備用類型。 這是一個類型占位符,在開發者調用該接口的時候會指定具體類型。
使用集合字面量
List , Set 和 Map 字面量也是可以參數化的。 參數化字面量和之前的字面量定義類似, 對于 List 或 Set 隻需要在聲明語句前加
<type>
字首, 對于 Map 隻需要在聲明語句前加
<keyType, valueType>
字首, 下面是參數化字面量的示例:
var names = <String>['Seth', 'Kathy', 'Lars'];
var uniqueNames = <String>{'Seth', 'Kathy', 'Lars'};
var pages = <String, String>{
'index.html': 'Homepage',
'robots.txt': 'Hints for web robots',
'humans.txt': 'We are people, not machines'
};
使用泛型類型的構造函數
在調用構造函數的時,在類名字後面使用尖括号(<…>)來指定泛型類型。 例如:
下面代碼建立了一個 key 為 integer, value 為 View 的 map 對象:
運作時中的泛型集合
Dart 中泛型類型是 固化的,也就是說它們在運作時是攜帶着類型資訊的。 例如, 在運作時檢測集合的類型:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
print(names is List<String>); // true
提示: 相反,Java中的泛型會被 擦除 ,也就是說在運作時泛型類型參數的資訊是不存在的。 在Java中,可以測試對象是否為類型, 但無法測試它是否為
List
。
List<String>
限制泛型類型
使用泛型類型的時候, 可以使用 extends 實作參數類型的限制。
class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}
class Extender extends SomeBaseClass {...}
可以使用 SomeBaseClass 或其任意子類作為通用參數:
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
也可以不指定泛型參數:
var foo = Foo();
print(foo); // Instance of 'Foo<SomeBaseClass>'
指定任何非 SomeBaseClass 類型會導緻錯誤:
使用泛型函數
最初,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;
}
這裡的
first (<T>)
泛型可以在如下地方使用參數
T
:
函數的傳回值類型 (
T
).
參數的類型 (
List<T>
).
局部變量的類型 (
T tmp
).
關于泛型的更多資訊,參考 使用泛型函數