簡述:
我們將繼續Dart語法的第二篇集合,雖然集合在第一篇中已經介紹的差不多,但是在這篇文章中將會更加全面介紹有關Dart中的集合,因爲之前只是介紹了dart:core包中的List、Set、Map,實際上在dart中還提供一個非常豐富的dart:collection包, 看過集合源碼小夥伴都知道dart:core包中的集合實際上是委託到dart:collection包中實現的,所以下面我也會從源碼的角度去把兩者聯繫起來。當然這裏也只會選擇幾個常用的集合作爲介紹。
一、List
在dart中的List集合是具有長度的可索引對象集合,它沒有委託dart:collection包中集合實現,完全由內部自己實現。
-
初始化
main() { //初始化一:直接使用[]形式初始化 List<String> colorList1 = ['red', 'yellow', 'blue', 'green']; //初始化二: var + 泛型 var colorList2 = <String> ['red', 'yellow', 'blue', 'green']; //初始化三: 初始化定長集合 List<String> colorList3 = List(4);//初始化指定大小爲4的集合, colorList3.add('deepOrange');//注意: 一旦指定了集合長度,不能再調用add方法,否則會拋出Cannot add to a fixed-length list。也容易理解因爲一個定長的集合不能再擴展了。 print(colorList3[2]);//null,此外初始化4個元素默認都是null //初始化四: 初始化空集合且是可變長的 List<String> colorList4 = List();//相當於List<String> colorList4 = [] colorList4[2] = 'white';//這裏會報錯,[]=實際上就是一個運算符重載,表示修改指定index爲2的元素爲white,然而它長度爲0所以找不到index爲2元素,所以會拋出IndexOutOfRangeException }
-
遍歷
main() { List<String> colorList = ['red', 'yellow', 'blue', 'green']; //for-i遍歷 for(var i = 0; i < colorList.length; i++) {//可以使用var或int print(colorList[i]); } //forEach遍歷 colorList.forEach((color) => print(color));//forEach的參數爲Function. =>使用了箭頭函數 //for-in遍歷 for(var color in colorList) { print(color); } //while+iterator迭代器遍歷,類似Java中的iteator while(colorList.iterator.moveNext()) { print(colorList.iterator.current); } }
-
常用的函數
main() { List<String> colorList = ['red', 'yellow', 'blue', 'green']; colorList.add('white');//和Kotlin類似通過add添加一個新的元素 List<String> newColorList = ['white', 'black']; colorList.addAll(newColorList);//addAll添加批量元素 print(colorList[2]);//可以類似Kotlin一樣,直接使用數組下標形式訪問元素 print(colorList.length);//獲取集合的長度,這個Kotlin不一樣,Kotlin中使用的是size colorList.insert(1, 'black');//在集合指定index位置插入指定的元素 colorList.removeAt(2);//移除集合指定的index=2的元素,第3個元素 colorList.clear();//清除所有元素 print(colorList.sublist(1,3));//截取子集合 print(colorList.getRange(1, 3));//獲取集合中某個範圍元素 print(colorList.join('<--->'));//類似Kotlin中的joinToString方法,輸出: red<--->yellow<--->blue<--->green print(colorList.isEmpty); print(colorList.contains('green')); }
-
構造函數源碼分析
dart中的List有很多個構造器,一個主構造器和多個命名構造器。主構造器中有個length可選參數.
external factory List([int length]);//主構造器,傳入length可選參數,默認爲0 external factory List.filled(int length, E fill, {bool growable = false});//filled命名構造器,只能聲明定長的數組 external factory List.from(Iterable elements, {bool growable = true}); factory List.of(Iterable<E> elements, {bool growable = true}) => List<E>.from(elements, growable: growable);//委託給List.from構造器來實現 external factory List.unmodifiable(Iterable elements);
-
exteranl關鍵字(插播一條內容)
注意: 問題來了,可能大家看到List源碼的時候一臉懵逼,構造函數沒有具體的實現。不知道有沒有注意 到exteranl 關鍵字。external修飾的函數具有一種實現函數聲明和實現體分離的特性。這下應該就明白了,也就是對應實現在別的地方。實際上你可以在DartSDK中的源碼找到,以List舉例,對應的是
sdk/sdk_nnbd/lib/_internal/vm/lib/array_patch.dart
, 此外對應的external函數實現會有一個 @patch註解 修飾.
@patch
class List<E> {
//對應的是List主構造函數的實現
@patch
factory List([int length]) native "List_new";//實際上這裏是通過native層的c++數組來實現,具體可參考runtime/lib/array.cc
//對應的是List.filled構造函數的實現,fill是需要填充元素值, 默認growable是false,默認不具有擴展功能
@patch
factory List.filled(int length, E fill, {bool growable: false}) {
var result = growable ? new _GrowableList<E>(length) : new _List<E>(length);//可以看到如果是可變長,就會創建一個_GrowableList,否則就創建內部私有的_List
if (fill != null) {//fill填充元素值不爲null,就返回length長度填充值爲fill的集合
for (int i = 0; i < length; i++) {
result[i] = fill;
}
}
return result;//否則直接返回相應長度的空集合
}
//對應的是List.from構造函數的實現,可將Iterable的集合加入到一個新的集合中,默認growable是true,默認具備擴展功能
@patch
factory List.from(Iterable elements, {bool growable: true}) {
if (elements is EfficientLengthIterable<E>) {
int length = elements.length;
var list = growable ? new _GrowableList<E>(length) : new _List<E>(length);//如果是可變長,就會創建一個_GrowableList,否則就創建內部私有的_List
if (length > 0) {
//只有在必要情況下創建iterator
int i = 0;
for (var element in elements) {
list[i++] = element;
}
}
return list;
}
//如果elements是一個Iterable<E>,就不需要爲每個元素做類型測試
//因爲在一般情況下,如果elements是Iterable<E>,在開始循環之前會用單個類型測試替換其中每個元素的類型測試。但是注意下: 等等,我發現下面這段源碼好像有點問題,難道是我眼神不好,if和else內部執行代碼一樣。
if (elements is Iterable<E>) {
//創建一個_GrowableList
List<E> list = new _GrowableList<E>(0);
//遍歷elements將每個元素重新加入到_GrowableList中
for (E e in elements) {
list.add(e);
}
//如果是可變長的直接返回這個list即可
if (growable) return list;
//否則調用makeListFixedLength使得集合變爲定長集合,實際上調用native層的c++實現
return makeListFixedLength(list);
} else {
List<E> list = new _GrowableList<E>(0);
for (E e in elements) {
list.add(e);
}
if (growable) return list;
return makeListFixedLength(list);
}
}
//對應的是List.unmodifiable構造函數的實現
@patch
factory List.unmodifiable(Iterable elements) {
final result = new List<E>.from(elements, growable: false);
//這裏利用了List.from構造函數創建一個定長的集合result
return makeFixedListUnmodifiable(result);
}
...
}
對應的List.from
sdk的源碼解析
//sdk/lib/_internal/vm/lib/internal_patch.dart中的makeListFixedLength
@patch
List<T> makeListFixedLength<T>(List<T> growableList)
native "Internal_makeListFixedLength";
//runtime/lib/growable_array.cc 中的Internal_makeListFixedLength
DEFINE_NATIVE_ENTRY(Internal_makeListFixedLength, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(GrowableObjectArray, array,
arguments->NativeArgAt(0));
return Array::MakeFixedLength(array, /* unique = */ true);//調用Array::MakeFixedLength C++方法變爲定長集合
}
//runtime/vm/object.cc中的Array::MakeFixedLength 返回一個RawArray
RawArray* Array::MakeFixedLength(const GrowableObjectArray& growable_array, bool unique) {
ASSERT(!growable_array.IsNull());
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
intptr_t used_len = growable_array.Length();
//拿到泛型類型參數,然後準備複製它們
const TypeArguments& type_arguments =
TypeArguments::Handle(growable_array.GetTypeArguments());
//如果集合爲空
if (used_len == 0) {
//如果type_arguments是空,那麼它就是一個原生List,不帶泛型類型參數的
if (type_arguments.IsNull() && !unique) {
//這是一個原生List(沒有泛型類型參數)集合並且是非unique,直接返回空數組
return Object::empty_array().raw();
}
// 根據傳入List的泛型類型參數,創建一個新的空的數組
Heap::Space space = thread->IsMutatorThread() ? Heap::kNew : Heap::kOld;//如果是MutatorThread就開闢新的內存空間否則複用舊的
Array& array = Array::Handle(zone, Array::New(0, space));//創建一個新的空數組array
array.SetTypeArguments(type_arguments);//設置拿到的類型參數
return array.raw();//返回一個相同泛型參數的新數組
}
//如果集合不爲空,取出growable_array中的data數組,且返回一個帶數據新的數組array
const Array& array = Array::Handle(zone, growable_array.data());
ASSERT(array.IsArray());
array.SetTypeArguments(type_arguments);//設置拿到的類型參數
//這裏主要是回收原來的growable_array,數組長度置爲0,內部data數組置爲空數組
growable_array.SetLength(0);
growable_array.SetData(Object::empty_array());
//注意: 定長數組實現的關鍵點來了,會調用Truncate方法將array截斷used_len長度
array.Truncate(used_len);
return array.raw();//最後返回array.raw()
}
總結一下List.from
的源碼實現,首先傳入elements的Iterate<E>
, 如果elements不帶泛型參數,也就是所謂的原生集合類型,並且是非unique,直接返回空數組; 如果帶泛型參數空集合,那麼會創建新的空集合並帶上原來泛型參數返回;如果是帶泛型參數非空集合,會取出其中data數組,來創建一個新的複製原來數據的集合並帶上原來泛型參數返回,最後需要截斷把數組截斷成原始數組長度。
- 爲什麼需要exteranl function
關鍵就是在於它能實現聲明和實現分離,這樣就能複用同一套對外API的聲明,然後對應多套多平臺的實現,如果對源碼感興趣的小夥伴就會發現相同API聲明在js中也有另一套實現,這樣不管是dart for web 還是dart for vm對於上層開發而言都是一套API,對於上層開發者是透明的。
二、Set
dart:core包中的Set集合實際上是委託到dart:collection中的LinkedHashSet來實現的。集合Set和列表List的區別在於 集合中的元素是不能重複 的。所以添加重複的元素時會返回false,表示添加不成功.
-
Set初始化方式
main() { Set<String> colorSet= {'red', 'yellow', 'blue', 'green'};//直接使用{}形式初始化 var colorList = <String> {'red', 'yellow', 'blue', 'green'}; }
-
集合中的交、並、補集,在Kotlin並沒有直接給到計算集合交、並、補的API
main() { var colorSet1 = {'red', 'yellow', 'blue', 'green'}; var colorSet2 = {'black', 'yellow', 'blue', 'green', 'white'}; print(colorSet1.intersection(colorSet2));//交集-->輸出: {'yellow', 'blue', 'green'} print(colorSet1.union(colorSet2));//並集--->輸出: {'black', 'red', 'yellow', 'blue', 'green', 'white'} print(colorSet1.difference(colorSet2));//補集--->輸出: {'red'} }
-
Set的遍歷方式(和List一樣)
main() { Set<String> colorSet = {'red', 'yellow', 'blue', 'green'}; //for-i遍歷 for (var i = 0; i < colorSet.length; i++) { //可以使用var或int print(colorSet[i]); } //forEach遍歷 colorSet.forEach((color) => print(color)); //forEach的參數爲Function. =>使用了箭頭函數 //for-in遍歷 for (var color in colorSet) { print(color); } //while+iterator迭代器遍歷,類似Java中的iteator while (colorSet.iterator.moveNext()) { print(colorSet.iterator.current); } }
-
構造函數源碼分析
factory Set() = LinkedHashSet<E>; //主構造器委託到LinkedHashSet主構造器 factory Set.identity() = LinkedHashSet<E>.identity; //Set的命名構造器identity委託給LinkedHashSet的identity factory Set.from(Iterable elements) = LinkedHashSet<E>.from;//Set的命名構造器from委託給LinkedHashSet的from factory Set.of(Iterable<E> elements) = LinkedHashSet<E>.of;//Set的命名構造器of委託給LinkedHashSet的of
-
對應LinkedHashSet的源碼分析,篇幅有限感興趣可以去深入研究
abstract class LinkedHashSet<E> implements Set<E> { //LinkedHashSet主構造器聲明帶了三個函數類型參數作爲可選參數,同樣是通過exteranl實現聲明和實現分離,要深入可找到對應的@Patch實現 external factory LinkedHashSet( {bool equals(E e1, E e2), int hashCode(E e), bool isValidKey(potentialKey)}); //LinkedHashSet命名構造器from factory LinkedHashSet.from(Iterable elements) { //內部直接創建一個LinkedHashSet對象 LinkedHashSet<E> result = LinkedHashSet<E>(); //並將傳入elements元素遍歷加入到LinkedHashSet中 for (final element in elements) { result.add(element); } return result; } //LinkedHashSet命名構造器of,首先創建一個LinkedHashSet對象,通過級聯操作直接通過addAll方法將元素加入到elements factory LinkedHashSet.of(Iterable<E> elements) => LinkedHashSet<E>()..addAll(elements); void forEach(void action(E element)); Iterator<E> get iterator; }
-
對應的
sdk/lib/_internal/vm/lib/collection_patch.dart
中的@Patch LinkedHashSet
@patch class LinkedHashSet<E> { @patch factory LinkedHashSet( {bool equals(E e1, E e2), int hashCode(E e), bool isValidKey(potentialKey)}) { if (isValidKey == null) { if (hashCode == null) { if (equals == null) { return new _CompactLinkedHashSet<E>(); //可選參數都爲null,默認創建_CompactLinkedHashSet } hashCode = _defaultHashCode; } else { if (identical(identityHashCode, hashCode) && identical(identical, equals)) { return new _CompactLinkedIdentityHashSet<E>();//創建_CompactLinkedIdentityHashSet } equals ??= _defaultEquals; } } else { hashCode ??= _defaultHashCode; equals ??= _defaultEquals; } return new _CompactLinkedCustomHashSet<E>(equals, hashCode, isValidKey);//可選參數identical,默認創建_CompactLinkedCustomHashSet } @patch factory LinkedHashSet.identity() => new _CompactLinkedIdentityHashSet<E>(); }
三、Map
dart:core 包中的 Map集合 實際上是 委託到dart:collection中的LinkedHashMap 來實現的。集合Map和Kotlin類似,key-value形式存儲,並且 Map對象的中key是不能重複的
-
Map初始化方式
main() { Map<String, int> colorMap = {'white': 0xffffffff, 'black':0xff000000};//使用{key:value}形式初始化 var colorMap = <String, int>{'white': 0xffffffff, 'black':0xff000000}; var colorMap = Map<String, int>();//創建一個空的Map集合 //實際上等價於下面代碼,後面會通過源碼說明 var colorMap = LinkedHashMap<String, int>(); }
-
Map中常用的函數
main() { Map<String, int> colorMap = {'white': 0xffffffff, 'black':0xff000000}; print(colorMap.containsKey('green'));//false print(colorMap.containsValue(0xff000000));//true print(colorMap.keys.toList());//['white','black'] print(colorMap.values.toList());//[0xffffffff, 0xff000000] colorMap['white'] = 0xfffff000;//修改指定key的元素 colorMap.remove('black');//移除指定key的元素 }
-
Map的遍歷方式
main() { Map<String, int> colorMap = {'white': 0xffffffff, 'black':0xff000000}; //for-each key-value colorMap.forEach((key, value) => print('color is $key, color value is $value')); }
-
Map.fromIterables將List集合轉化成Map
main() { List<String> colorKeys = ['white', 'black']; List<int> colorValues = [0xffffffff, 0xff000000]; Map<String, int> colorMap = Map.fromIterables(colorKeys, colorValues); }
-
構造函數源碼分析
external factory Map(); //主構造器交由外部@Patch實現, 實際上對應的@Patch實現還是委託給LinkedHashMap factory Map.from(Map other) = LinkedHashMap<K, V>.from;//Map的命名構造器from委託給LinkedHashMap的from factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;//Map的命名構造器of委託給LinkedHashMap的of external factory Map.unmodifiable(Map other);//unmodifiable構造器交由外部@Patch實現 factory Map.identity() = LinkedHashMap<K, V>.identity;//Map的命名構造器identity交由外部@Patch實現 factory Map.fromIterable(Iterable iterable, {K key(element), V value(element)}) = LinkedHashMap<K, V>.fromIterable;//Map的命名構造器fromIterable委託給LinkedHashMap的fromIterable factory Map.fromIterables(Iterable<K> keys, Iterable<V> values) = LinkedHashMap<K, V>.fromIterables;//Map的命名構造器fromIterables委託給LinkedHashMap的fromIterables
-
對應LinkedHashMap構造函數源碼分析
abstract class LinkedHashMap<K, V> implements Map<K, V> { //主構造器交由外部@Patch實現 external factory LinkedHashMap( {bool equals(K key1, K key2), int hashCode(K key), bool isValidKey(potentialKey)}); //LinkedHashMap命名構造器identity交由外部@Patch實現 external factory LinkedHashMap.identity(); //LinkedHashMap的命名構造器from factory LinkedHashMap.from(Map other) { //創建一個新的LinkedHashMap對象 LinkedHashMap<K, V> result = LinkedHashMap<K, V>(); //遍歷other中的元素,並添加到新的LinkedHashMap對象 other.forEach((k, v) { result[k] = v; }); return result; } //LinkedHashMap的命名構造器of,創建一個新的LinkedHashMap對象,通過級聯操作符調用addAll批量添加map到新的LinkedHashMap中 factory LinkedHashMap.of(Map<K, V> other) => LinkedHashMap<K, V>()..addAll(other); //LinkedHashMap的命名構造器fromIterable,傳入的參數是iterable對象、key函數參數、value函數參數兩個可選參數 factory LinkedHashMap.fromIterable(Iterable iterable, {K key(element), V value(element)}) { //創建新的LinkedHashMap對象,通過MapBase中的static方法_fillMapWithMappedIterable,給新的map添加元素 LinkedHashMap<K, V> map = LinkedHashMap<K, V>(); MapBase._fillMapWithMappedIterable(map, iterable, key, value); return map; } //LinkedHashMap的命名構造器fromIterables factory LinkedHashMap.fromIterables(Iterable<K> keys, Iterable<V> values) { //創建新的LinkedHashMap對象,通過MapBase中的static方法_fillMapWithIterables,給新的map添加元素 LinkedHashMap<K, V> map = LinkedHashMap<K, V>(); MapBase._fillMapWithIterables(map, keys, values); return map; } } //MapBase中的_fillMapWithMappedIterable static void _fillMapWithMappedIterable( Map map, Iterable iterable, key(element), value(element)) { key ??= _id; value ??= _id; for (var element in iterable) {//遍歷iterable,給map對應複製 map[key(element)] = value(element); } } // MapBase中的_fillMapWithIterables static void _fillMapWithIterables(Map map, Iterable keys, Iterable values) { Iterator keyIterator = keys.iterator;//拿到keys的iterator Iterator valueIterator = values.iterator;//拿到values的iterator bool hasNextKey = keyIterator.moveNext();//是否有NextKey bool hasNextValue = valueIterator.moveNext();//是否有NextValue while (hasNextKey && hasNextValue) {//同時遍歷迭代keys,values map[keyIterator.current] = valueIterator.current; hasNextKey = keyIterator.moveNext(); hasNextValue = valueIterator.moveNext(); } if (hasNextKey || hasNextValue) {//最後如果其中只要有一個爲true,說明key與value的長度不一致,拋出異常 throw ArgumentError("Iterables do not have same length."); } }
-
Map的@Patch對應實現,對應
sdk/lib/_internal/vm/lib/map_patch.dart
中@patch class Map<K, V> { @patch factory Map.unmodifiable(Map other) { return new UnmodifiableMapView<K, V>(new Map<K, V>.from(other)); } @patch factory Map() => new LinkedHashMap<K, V>(); //可以看到Map的創建實際上最終還是對應創建了LinkedHashMap<K, V> }
四、Queue
Queue隊列顧名思義先進先出的一種數據結構,在Dart對隊列也做了一定的支持, 實際上Queue的實現是委託給ListQueue來實現。 Queue繼承於EfficientLengthIterable<E>
接口,然後EfficientLengthIterable<E>
接口又繼承了Iterable<E>
.所以意味着Queue可以向List那樣使用豐富的操作函數。並且由Queue派生出了 DoubleLinkedQueue
和ListQueue
-
初始化
import 'dart:collection';//注意: Queue位於dart:collection包中需要導包 main() { //通過主構造器初始化 var queueColors = Queue(); queueColors.addFirst('red'); queueColors.addLast('yellow'); queueColors.add('blue'); //通過from命名構造器初始化 var queueColors2 = Queue.from(['red', 'yellow', 'blue']); //通過of命名構造器初始化 var queueColors3 = Queue.of(['red', 'yellow', 'blue']); }
-
常用的函數
import 'dart:collection';//注意: Queue位於dart:collection包中需要導包 main() { var queueColors = Queue() ..addFirst('red') ..addLast('yellow') ..add('blue') ..addAll(['white','black']) ..remove('black') ..clear(); }
-
遍歷
import 'dart:collection'; //注意: Queue位於dart:collection包中需要導包 main() { Queue<String> colorQueue = Queue.from(['red', 'yellow', 'blue', 'green']); //for-i遍歷 for (var i = 0; i < colorQueue.length; i++) { //可以使用var或int print(colorQueue.elementAt(i)); //注意: 獲取隊列中的元素不用使用colorQueue[i], 因爲Queue內部並沒有去實現[]運算符重載 } //forEach遍歷 colorQueue.forEach((color) => print(color)); //forEach的參數爲Function. =>使用了箭頭函數 //for-in遍歷 for (var color in colorQueue) { print(color); } }
-
構造函數源碼分析
factory Queue() = ListQueue<E>;//委託給ListQueue<E>主構造器 factory Queue.from(Iterable elements) = ListQueue<E>.from;//委託給ListQueue<E>的命名構造器from factory Queue.of(Iterable<E> elements) = ListQueue<E>.of;//委託給ListQueue<E>的命名構造器of
-
對應的ListQueue的源碼分析
class ListQueue<E> extends ListIterable<E> implements Queue<E> { static const int _INITIAL_CAPACITY = 8;//默認隊列的初始化容量是8 List<E?> _table; int _head; int _tail; int _modificationCount = 0; ListQueue([int? initialCapacity]) : _head = 0, _tail = 0, _table = List<E?>(_calculateCapacity(initialCapacity));//有趣的是可以看到ListQueque內部實現是一個List<E?>集合, E?還是一個泛型類型爲可空類型,但是目前dart的可空類型特性還在實驗中,不過可以看到它的源碼中已經用起來了。 //計算隊列所需要容量大小 static int _calculateCapacity(int? initialCapacity) { //如果initialCapacity爲null或者指定的初始化容量小於默認的容量就是用默認的容量大小 if (initialCapacity == null || initialCapacity < _INITIAL_CAPACITY) { return _INITIAL_CAPACITY; } else if (!_isPowerOf2(initialCapacity)) {//容量大小不是2次冪 return _nextPowerOf2(initialCapacity);//找到大小是接近number的2次冪的數 } assert(_isPowerOf2(initialCapacity));//斷言檢查 return initialCapacity;//最終返回initialCapacity,返回的容量大小一定是2次冪的數 } //判斷容量大小是否是2次冪 static bool _isPowerOf2(int number) => (number & (number - 1)) == 0; //找到大小是接近number的二次冪的數 static int _nextPowerOf2(int number) { assert(number > 0); number = (number << 1) - 1; for (;;) { int nextNumber = number & (number - 1); if (nextNumber == 0) return number; number = nextNumber; } } //ListQueue的命名構造函數from factory ListQueue.from(Iterable<dynamic> elements) { //判斷elements 是否是List<dynamic>類型 if (elements is List<dynamic>) { int length = elements.length;//取出長度 ListQueue<E> queue = ListQueue<E>(length + 1);//創建length + 1長度的ListQueue assert(queue._table.length > length);//必須保證新創建的queue的長度大於傳入elements的長度 for (int i = 0; i < length; i++) { queue._table[i] = elements[i] as E;//然後就是給新queue中的元素賦值,注意需要強轉成泛型類型E } queue._tail = length;//最終移動隊列的tail尾部下標,因爲可能存在實際長度大於實際元素長度 return queue; } else { int capacity = _INITIAL_CAPACITY; if (elements is EfficientLengthIterable) {//如果是EfficientLengthIterable類型,就將elements長度作爲初始容量不是就使用默認容量 capacity = elements.length; } ListQueue<E> result = ListQueue<E>(capacity); for (final element in elements) { result.addLast(element as E);//通過addLast從隊列尾部插入 } return result;//最終返回result } } //ListQueue的命名構造函數of factory ListQueue.of(Iterable<E> elements) => ListQueue<E>()..addAll(elements); //直接創建ListQueue<E>()並通過addAll把elements加入到新的ListQueue中 ... }
五、LinkedList
在dart中LinkedList比較特殊,它不是一個帶泛型集合,因爲它泛型類型上界是LinkedListEntry
, 內部的數據結構實現是一個雙鏈表,鏈表的結點是LinkedListEntry
的子類,且內部維護了_next
和_previous
指針。此外它並沒有實現List接口
-
初始化
import 'dart:collection'; //注意: LinkedList位於dart:collection包中需要導包 main() { var linkedList = LinkedList<LinkedListEntryImpl<int>>(); var prevLinkedEntry = LinkedListEntryImpl<int>(99); var currentLinkedEntry = LinkedListEntryImpl<int>(100); var nextLinkedEntry = LinkedListEntryImpl<int>(101); linkedList.add(currentLinkedEntry); currentLinkedEntry.insertBefore(prevLinkedEntry);//在當前結點前插入一個新的結點 currentLinkedEntry.insertAfter(nextLinkedEntry);//在當前結點後插入一個新的結點 linkedList.forEach((entry) => print('${entry.value}')); } //需要定義一個LinkedListEntry子類 class LinkedListEntryImpl<T> extends LinkedListEntry<LinkedListEntryImpl<T>> { final T value; LinkedListEntryImpl(this.value); @override String toString() { return "value is $value"; } }
-
常用的函數
currentLinkedEntry.insertBefore(prevLinkedEntry);//在當前結點前插入一個新的結點 currentLinkedEntry.insertAfter(nextLinkedEntry);//在當前結點後插入一個新的結點 currentLinkedEntry.previous;//獲取當前結點的前一個結點 currentLinkedEntry.next;//獲取當前結點的後一個結點 currentLinkedEntry.list;//獲取LinkedList currentLinkedEntry.unlink();//把當前結點entry從LinkedList中刪掉
-
遍歷
//forEach迭代 linkedList.forEach((entry) => print('${entry.value}')); //for-i迭代 for (var i = 0; i < linkedList.length; i++) { print('${linkedList.elementAt(i).value}'); } //for-in迭代 for (var element in linkedList) { print('${element.value}'); }
六、HashMap
-
初始化
import 'dart:collection'; //注意: HashMap位於dart:collection包中需要導包 main() { var hashMap = HashMap();//通過HashMap主構造器初始化 hashMap['a'] = 1; hashMap['b'] = 2; hashMap['c'] = 3; var hashMap2 = HashMap.from(hashMap);//通過HashMap命名構造器from初始化 var hashMap3 = HashMap.of(hashMap);//通過HashMap命名構造器of初始化 var keys = ['a', 'b', 'c']; var values = [1, 2, 3] var hashMap4 = HashMap.fromIterables(keys, values);//通過HashMap命名構造器fromIterables初始化 hashMap2.forEach((key, value) => print('key: $key value: $value')); }
-
常用的函數
import 'dart:collection'; //注意: HashMap位於dart:collection包中需要導包 main() { var hashMap = HashMap();//通過HashMap主構造器初始化 hashMap['a'] = 1; hashMap['b'] = 2; hashMap['c'] = 3; print(hashMap.containsKey('a'));//false print(hashMap.containsValue(2));//true print(hashMap.keys.toList());//['a','b','c'] print(hashMap.values.toList());//[1, 2, 3] hashMap['a'] = 55;//修改指定key的元素 hashMap.remove('b');//移除指定key的元素 }
-
遍歷
import 'dart:collection'; //注意: HashMap位於dart:collection包中需要導包 main() { var hashMap = HashMap();//通過HashMap主構造器初始化 hashMap['a'] = 1; hashMap['b'] = 2; hashMap['c'] = 3; //for-each key-value hashMap.forEach((key, value) => print('key is $key, value is $value')); }
-
構造函數源碼分析
//主構造器交由外部@Patch實現 external factory HashMap( {bool equals(K key1, K key2), int hashCode(K key), bool isValidKey(potentialKey)}); //HashMap命名構造器identity交由外部@Patch實現 external factory HashMap.identity(); //HashMap命名構造器from factory HashMap.from(Map other) { //創建一個HashMap對象 Map<K, V> result = HashMap<K, V>(); //遍歷other集合並把元素賦值給新的HashMap對象 other.forEach((k, v) { result[k] = v; }); return result; } //HashMap命名構造器of,把other添加到新創建HashMap對象 factory HashMap.of(Map<K, V> other) => HashMap<K, V>()..addAll(other); //HashMap命名構造器fromIterable factory HashMap.fromIterable(Iterable iterable, {K key(element), V value(element)}) { Map<K, V> map = HashMap<K, V>();//創建一個新的HashMap對象 MapBase._fillMapWithMappedIterable(map, iterable, key, value);//通過MapBase中的_fillMapWithMappedIterable賦值給新的HashMap對象 return map; } //HashMap命名構造器fromIterables factory HashMap.fromIterables(Iterable<K> keys, Iterable<V> values) { Map<K, V> map = HashMap<K, V>();//創建一個新的HashMap對象 MapBase._fillMapWithIterables(map, keys, values);//通過MapBase中的_fillMapWithIterables賦值給新的HashMap對象 return map; }
-
HashMap對應的@Patch源碼實現,
sdk/lib/_internal/vm/lib/collection_patch.dart
@patch class HashMap<K, V> { @patch factory HashMap( {bool equals(K key1, K key2), int hashCode(K key), bool isValidKey(potentialKey)}) { if (isValidKey == null) { if (hashCode == null) { if (equals == null) { return new _HashMap<K, V>();//創建私有的_HashMap對象 } hashCode = _defaultHashCode; } else { if (identical(identityHashCode, hashCode) && identical(identical, equals)) { return new _IdentityHashMap<K, V>();//創建私有的_IdentityHashMap對象 } equals ??= _defaultEquals; } } else { hashCode ??= _defaultHashCode; equals ??= _defaultEquals; } return new _CustomHashMap<K, V>(equals, hashCode, isValidKey);//創建私有的_CustomHashMap對象 } @patch factory HashMap.identity() => new _IdentityHashMap<K, V>(); Set<K> _newKeySet(); }
七、Map、HashMap、LinkedHashMap、SplayTreeMap區別
在Dart中還有一個SplayTreeMap,它的初始化、常用的函數和遍歷方式和LinkedHashMap、HashMap使用類似。但是Map、HashMap、LinkedHashMap、SplayTreeMap有什麼區別呢。
-
Map
Map是key-value鍵值對集合。在Dart中的Map中的每個條目都可以迭代的。迭代順序取決於HashMap,LinkedHashMap或SplayTreeMap的實現。如果您使用Map構造函數創建實例,則默認情況下會創建一個LinkedHashMap。
-
HashMap
HashMap不保證插入順序。如果先插入key爲A的元素,然後再插入具有key爲B的另一個元素,則在遍歷
Map
時,有可能先獲得元素B。 -
LinkedHashMap
LinkedHashMap保證插入順序。根據插入順序對存儲在LinkedHashMap中的數據進行排序。如果先插入key爲A的元素,然後再插入具有key爲B的另一個元素,則在遍歷
Map
時,總是先取的key爲A的元素,然後再取的key爲B的元素。 -
SplayTreeMap
SplayTreeMap是一個自平衡二叉樹,它允許更快地訪問最近訪問的元素。基本操作如插入,查找和刪除可以在O(log(n))時間複雜度中完成。它通過使經常訪問的元素靠近樹的根來執行樹的旋轉。因此,如果需要更頻繁地訪問某些元素,則使用SplayTreeMap是一個不錯的選擇。但是,如果所有元素的數據訪問頻率幾乎相同,則使用SplayTreeMap是沒有用的。
八、命名構造函數from和of的區別以及使用建議
通過上述各個集合源碼可以看到,基本上每個集合(List、Set、LinkedHashSet、LinkedHashMap、Map、HashMap等)中都有from和of命名構造函數。可能有的人有疑問了,它們有什麼區別,各自的應用場景呢。其實答案從源碼中就看出一點了。以List,Map中的from和of爲例。
main() {
var map = {'a': 1, 'b': 2, 'c': 3};
var fromMap = Map.from(map); //返回類型是Map<dynamic, dynamic>
var ofMap = Map.of(map); //返回類型是Map<String, int>
var list = [1, 2, 3, 4];
var fromList = List.from(list); //返回類型是List<dynamic>
var ofList = List.of(list); //返回類型是List<int>
}
從上述例子可以看出List、Map中的from函數返回對應的集合泛型類型是 List<dynamic>
和 Map<dynamic, dynamic>
而of函數返回對應集合泛型類型實際類型是 List<int>
和 Map<String, int>
。我們都知道dynamic是一種無法確定的類型,在編譯期不檢查類型,只在運行器檢查類型,而具體類型是在編譯期檢查類型。而且從源碼中可以看到 from函數往往會處理比較複雜邏輯比如需要重新遍歷傳入的集合然後把元素加入到新的集合中,而of函數只需要創建一個新的對象通過addAll函數批量添加傳入的集合元素。
所以這裏爲了代碼效率考慮給出建議是: 如果你傳入的原有集合元素類型是確定的,請儘量使用of函數創建新的集合,否則就可以考慮使用from函數。
總結
到這裏我們dart語法系列第二篇就結束了,相信通過這篇文章大家對dart中的集合應該有了全面的瞭解,下面我們將繼續研究dart和Flutter相關內容。