Dart基礎之泛型

前言

若是你查過基本數組類型 List 的API文檔,會看到該類型其實是List<E><...>表示法將List標記爲通用(或參數化)類型 - 具備正式類型參數的類型。 按照慣例,大多數類型變量都有單字母名稱,例如E,T,S,K和V.html

爲何要用泛型

泛型的時候經常須要類型安全,但他們相比直接運行代碼會有更多的好處:git

  • 正確指定泛型類型會產生更好的生成代碼。(對於寫代碼而言)
  • 你可使用泛型來減小代碼重複。

若是你但願List只包含String,則能夠將其聲明爲List <String>(將其稱爲「字符串列表」)。 這樣,你,你的夥伴和你的工具,能夠明白將非字符串分配給列表多是一個錯誤。 舉個例子:github

var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // 靜態解析的時候就會提示錯誤
複製代碼

使用泛型的另外一個緣由是減小重複代碼。 泛型容許你在 多種類型之間共享單個接口和實現,同時仍然利用靜態分析。 例如,假設你建立了一個用於緩存對象的接口:web

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。 參數化文字就像你已經看到的文字同樣,除了你在開始括號以前添加<type>(對於List和Set)或<keyType,valueType>(對於maps)。 如下是使用類型文字的示例:工具

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'
};
複製代碼

使用帶有構造函數的參數化類型

要在使用構造函數時指定一個或多個類型,請將類型放在尖括號(<...>)後面的類名稱以後。 例如:測試

var nameSet = Set<String>.from(names);
複製代碼

如下代碼建立一個具備整數鍵和View類型值的map:

var views = Map<int, View>();
複製代碼

通用集合及其包含的類型

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> {
  // 在這裏實現
  String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}
複製代碼

可使用SomeBaseClass或其任何子類做爲通用參數:

var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
複製代碼

也能夠不指定泛型參數:

var foo = Foo();
print(foo); //'Foo<SomeBaseClass>'的實例 
複製代碼

指定任何非SomeBaseClass類型會致使錯誤:

var foo = Foo<Object>();//靜態解析報錯
複製代碼

使用泛型方法

最初,Dart的泛型支持僅限於classes。 一種稱新的語法稱爲泛型方法,容許在方法和函數上使用類型參數:

T first<T>(List<T> ts) {
  // 作一些初始化工做或者檢查錯誤...
  T tmp = ts[0];
  // 作一些額外的檢查或者處理...
  return tmp;
}
複製代碼

這裏,first(<T>)上的泛型類型參數容許你在多處使用類型參數T

  • 在函數的返回類型(T)中。
  • 在參數的類型(List<T>)中。
  • 在局部變量的類型(T tmp)。

更多關於泛型的信息,請查看運用泛型方法

相關文章
相關標籤/搜索