簡述:html
咱們將繼續Dart語法的第二篇集合,雖然集合在第一篇中已經介紹的差很少,可是在這篇文章中將會更加全面介紹有關Dart中的集合,由於以前只是介紹了dart:core包中的List、Set、Map,實際上在dart中還提供一個很是豐富的dart:collection包, 看過集合源碼小夥伴都知道dart:core包中的集合其實是委託到dart:collection包中實現的,因此下面我也會從源碼的角度去把二者聯繫起來。固然這裏也只會選擇幾個經常使用的集合做爲介紹。c++
在dart中的List集合是具備長度的可索引對象集合,它沒有委託dart:collection包中集合實現,徹底由內部本身實現。web
初始化api
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'));
}
複製代碼
構造函數源碼分析app
dart中的List有不少個構造器,一個主構造器和多個命名構造器。主構造器中有個length可選參數.ide
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數組,來建立一個新的複製原來數據的集合並帶上原來泛型參數返回,最後須要截斷把數組截斷成原始數組長度。
關鍵就是在於它能實現聲明和實現分離,這樣就能複用同一套對外API的聲明,而後對應多套多平臺的實現,若是對源碼感興趣的小夥伴就會發現相同API聲明在js中也有另外一套實現,這樣無論是dart for web 仍是dart for vm對於上層開發而言都是一套API,對於上層開發者是透明的。
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>();
}
複製代碼
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隊列顧名思義先進先出的一種數據結構,在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中
...
}
複製代碼
在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}');
}
複製代碼
初始化
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();
}
複製代碼
在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是沒有用的。
經過上述各個集合源碼能夠看到,基本上每一個集合(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相關內容。