日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

kotlin 添加第一个 集合_Flutter开发必学Dart语法篇之集合操作符函数与源码分析...

發(fā)布時間:2023/12/2 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 kotlin 添加第一个 集合_Flutter开发必学Dart语法篇之集合操作符函数与源码分析... 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

簡述:

在上一篇文章中,我們?nèi)娴胤治隽顺S眉系氖褂靡约凹喜糠衷创a的分析。那么這一節(jié)講點更實用的內(nèi)容,絕對可以提高你的Flutter開發(fā)效率的函數(shù),那就是集合中常用的操作符函數(shù)。這次說的內(nèi)容的比較簡單就是怎么用,以及源碼內(nèi)部是怎么實現(xiàn)的。

一、`Iterable`

在dart中幾乎所有集合擁有的操作符函數(shù)(例如: map、every、where、reduce等)都是因為繼承或者實現(xiàn)了Iterable。

1、Iterable類關(guān)系圖

二、forEach

1、介紹

void forEach(void f(E element))

forEach在dart中用于遍歷和迭代集合,也是dart中操作集合最常用的方法之一。接收一個f(E element)函數(shù)作為參數(shù),返回值類型為空void.

2、使用方式

main() { var languages = ['Dart', 'Kotlin', 'Java', 'Javascript', 'Go', 'Python', 'Swift']; languages.forEach((language) => print('The language is $language'));//由于只有一個表達(dá)式,所以可以直接使用箭頭函數(shù)。 languages.forEach((language){ if(language == 'Dart' || language == 'Kotlin') { print('My favorite language is $language'); } });}

3、源碼解析

void forEach(void f(E element)) { //可以看到在forEach內(nèi)部實際上就是利用for-in迭代,每迭代一次就執(zhí)行一次f函數(shù), //并把當(dāng)前element回調(diào)出去 for (E element in this) f(element); }

三、map

1、介紹

Iterable map(T f(E e))

map函數(shù)主要用于集合中元素的映射,也可以映射轉(zhuǎn)化成其他類型的元素。可以看到map接收一個T f(E e)函數(shù)作為參數(shù),最后返回一個泛型參數(shù)為T的Iterable。實際上是返回了帶有元素的一個新的惰性Iterable, 然后通過迭代的時候,對每個元素都調(diào)用f函數(shù)。注意: f函數(shù)是一個接收泛型參數(shù)為E的元素,然后返回一個泛型參數(shù)為T的元素,這就是map可以將原集合中每個元素映射成其他類型元素的原因。

2、使用方式

main() { var languages = ['Dart', 'Kotlin', 'Java', 'Javascript', 'Go', 'Python', 'Swift']; print(languages.map((language) => 'develop language is ${language}').join('---')); }

3、源碼解析

以上面的例子為例,

  • 1、首先,需要明確一點,languages內(nèi)部本質(zhì)是一個_GrowableList, 我們都知道_GrowableList是繼承了ListBase,然后ListBase又mixin with ListMixin.所以languages.map函數(shù)調(diào)用就是調(diào)用ListMixin中的map函數(shù),實際上還是相當(dāng)于調(diào)用了自身的成員函數(shù)map.

以上面的例子為例,

  • 1、首先,需要明確一點,languages內(nèi)部本質(zhì)是一個_GrowableList, 我們都知道_GrowableList是繼承了ListBase,然后ListBase又mixin with ListMixin.所以languages.map函數(shù)調(diào)用就是調(diào)用ListMixin中的map函數(shù),實際上還是相當(dāng)于調(diào)用了自身的成員函數(shù)map.
@pragma("vm:entry-point")class _GrowableList extends ListBase {//_GrowableList是繼承了ListBase ...}abstract class ListBase extends Object with ListMixin {//ListBase mixin with ListMixin ...}2、然后可以看到ListMixin實際上實現(xiàn)了List,然后List繼承了EfficientLengthIterable,最后EfficientLengthIterable繼承Iterable,所以最終的map函數(shù)來自于Iterable但是具體的實現(xiàn)定義在ListMinxin中。abstract class ListMixin implements List { ... //可以看到這里是直接返回一個MappedListIterable,它是一個惰性Iterable Iterable map(T f(E element)) => MappedListIterable(this, f); ... }
  • 3、為什么是惰性的呢,可以看到它并不是直接返回轉(zhuǎn)化后的集合,而是返回一個帶有值的MappedListIterable的,如果不執(zhí)行`elementAt`方法,是不會觸發(fā)執(zhí)行map傳入的`f`函數(shù), 所以它是惰性的。
class MappedListIterable extends ListIterable { final Iterable _source;//_source存儲了所攜帶的原集合 final _Transformation _f;//_f函數(shù)存儲了map函數(shù)傳入的閉包, MappedListIterable(this._source, this._f); int get length => _source.length; //注意: 只有elementAt函數(shù)執(zhí)行的時候,才會觸發(fā)執(zhí)行_f方法,然后通過_source的elementAt函數(shù)取得原集合中的元素, //最后針對_source中的每個元素執(zhí)行_f函數(shù)處理。 T elementAt(int index) => _f(_source.elementAt(index));}
  • 4、一般不會單獨(dú)使用map函數(shù),因為單獨(dú)使用map的函數(shù)時,僅僅返回的是惰性的MappedListIterable。由上面的源碼可知,僅僅在elementAt調(diào)用的時候才會觸發(fā)map中的閉包。所以我們一般使用完map后會配合toList()、toSet()函數(shù)或者觸發(fā)elementAt函數(shù)的函數(shù)(例如這里的join)一起使用。
languages.map((language) => 'develop language is ${language}').toList();//toList()方法調(diào)用才會真正去執(zhí)行map中的閉包。languages.map((language) => 'develop language is ${language}').toSet();//toSet()方法調(diào)用才會真正去執(zhí)行map中的閉包。languages.map((language) => 'develop language is ${language}').join('---');//join()方法調(diào)用才會真正去執(zhí)行map中的閉包。 List toList({bool growable = true}) { List result; if (growable) { result = []..length = length; } else { result = List(length); } for (int i = 0; i < length; i++) { result[i] = this[i];//注意: 這里的this[i]實際上是運(yùn)算符重載了[],最終就是調(diào)用了elementAt函數(shù),這里才會真正的觸發(fā)map中的閉包, } return result; }

四、any

1、介紹

bool any(bool test(E element))

any函數(shù)主要用于檢查是否存在任意一個滿足條件的元素,只要匹配到第一個就返回true, 如果遍歷所有元素都不符合才返回false.
any函數(shù)接收一個bool test(E element)函數(shù)作為參數(shù),test函數(shù)回調(diào)一個E類型的element并返回一個bool類型的值。

2、使用方式

main() { bool isDartExisted = languages.any((language) => language == 'Dart');}

3、源碼解析

bool any(bool test(E element)) { int length = this.length;//獲取到原集合的length //遍歷原集合,只要找到符合test函數(shù)的條件,就返回true for (int i = 0; i < length; i++) { if (test(this[i])) return true; if (length != this.length) { throw ConcurrentModificationError(this); } } //遍歷完集合后,未找到符合條件的集合就返回false return false; }

五、every

1、介紹

bool every(bool test(E element))

every函數(shù)主要用于檢查是否集合所有元素都滿足條件,如果都滿足就返回true, 只要存在一個不滿足條件的就返回false.
every函數(shù)接收一個bool test(E element)函數(shù)作為參數(shù),test函數(shù)回調(diào)一個E類型的element并返回一個bool類型的值。

2、使用方式

main() { bool isDartAll = languages.every((language) => language == 'Dart');}

3、源碼解析

bool every(bool test(E element)) { //利用for-in遍歷集合,只要找到不符合test函數(shù)的條件,就返回false. for (E element in this) { if (!test(element)) return false; }//遍歷完集合后,找到所有元素符合條件就返回true return true; }

六、where

1、介紹

Iterable where(bool test(E element))

where函數(shù)主要用于過濾符合條件的元素,類似Kotlin中的filter的作用,最后返回符合條件元素的集合。
where函數(shù)接收一個bool test(E element)函數(shù)作為參數(shù),最后返回一個泛型參數(shù)為E的Iterable。類似map一樣,where這里也是返回一個惰性的Iterable, 然后對它的iterator進(jìn)行迭代,對每個元素都執(zhí)行test方法。

2、使用方式

main() { List numbers = [0, 3, 1, 2, 7, 12, 2, 4]; print(numbers.where((num) => num > 6));//輸出: (7,12) //注意: 這里是print的內(nèi)容實際上輸出的是Iterable的toString方法返回的內(nèi)容。}

3、源碼解析

  • 1、首先,需要明確一點numbers實際上是一個_GrowableList和map的分析原理類似,最終還是調(diào)用了ListMixin中的where函數(shù)。
//可以看到這里是直接返回一個WhereIterable對象,而不是返回過濾后元素集合,所以它返回的Iterable也是惰性的。Iterable where(bool test(E element)) => WhereIterable(this, test);
  • 2、然后,繼續(xù)深入研究下WhereIterable是如何實現(xiàn)的
class WhereIterable extends Iterable { final Iterable _iterable;//傳入的原集合 final _ElementPredicate _f;//傳入的where函數(shù)中閉包參數(shù) WhereIterable(this._iterable, this._f); //注意: 這里WhereIterable的迭代借助了iterator,這里是直接創(chuàng)建一個WhereIterator,并傳入元集合_iterable中的iterator以及過濾操作函數(shù)。 Iterator get iterator => new WhereIterator(_iterable.iterator, _f); // Specialization of [Iterable.map] to non-EfficientLengthIterable. Iterable map(T f(E element)) => new MappedIterable._(this, f);}
  • 3、然后,繼續(xù)深入研究下WhereIterator是如何實現(xiàn)的
class WhereIterator extends Iterator { final Iterator _iterator;//存儲集合中的iterator對象 final _ElementPredicate _f;//存儲where函數(shù)傳入閉包函數(shù) WhereIterator(this._iterator, this._f); //重寫moveNext函數(shù) bool moveNext() { //遍歷原集合的_iterator while (_iterator.moveNext()) { //注意: 這里會執(zhí)行_f函數(shù),如果滿足條件就會返回true, 不符合條件的直接略過,迭代下一個元素; //那么外部迭代時候,就可以通過current獲得當(dāng)前元素,這樣就實現(xiàn)了在原集合基礎(chǔ)上過濾拿到符合條件的元素。 if (_f(_iterator.current)) { return true; } } //迭代完_iterator所有元素后返回false,以此來終止外部迭代。 return false; } //重寫current的屬性方法 E get current => _iterator.current;}
  • 4、一般在使用的WhereIterator的時候,外部肯定還有一層while迭代,但是這個WhereIterator比較特殊,moveNext()的返回值由where中閉包函數(shù)參數(shù)返回值決定的,符合條件元素moveNext()就返回true,不符合就略過,迭代檢查下一個元素,直至整個集合迭代完畢,moveNext()返回false,以此也就終止了外部的迭代循環(huán)。
  • 5、上面分析,WhereIterable是惰性的,那它啥時候觸發(fā)呢? 沒錯就是在迭代它的iterator時候才會觸發(fā),以上面例子為例
print(numbers.where((num) => num > 6));//輸出: (7,12),最后會調(diào)用Iterable的toString方法返回的內(nèi)容。//看下Iterable的toString方法實現(xiàn)String toString() => IterableBase.iterableToShortString(this, '(', ')');//這就是為啥輸出樣式是 (7,12)//繼續(xù)查看IterableBase.iterableToShortString static String iterableToShortString(Iterable iterable, [String leftDelimiter = '(', String rightDelimiter = ')']) { if (_isToStringVisiting(iterable)) { if (leftDelimiter == "(" && rightDelimiter == ")") { // Avoid creating a new string in the "common" case. return "(...)"; } return "$leftDelimiter...$rightDelimiter"; } List parts = []; _toStringVisiting.add(iterable); try { _iterablePartsToStrings(iterable, parts);//注意:這里實際上就是通過將iterable轉(zhuǎn)化成List,內(nèi)部就是通過迭代iterator,以此會觸發(fā)WhereIterator中的_f函數(shù)。 } finally { assert(identical(_toStringVisiting.last, iterable)); _toStringVisiting.removeLast(); } return (StringBuffer(leftDelimiter) ..writeAll(parts, ", ") ..write(rightDelimiter)) .toString(); } /// Convert elements of [iterable] to strings and store them in [parts]. 這個函數(shù)代碼實現(xiàn)比較多,這里給出部分代碼void _iterablePartsToStrings(Iterable iterable, List parts) { ... int length = 0; int count = 0; Iterator it = iterable.iterator; // Initial run of elements, at least headCount, and then continue until // passing at most lengthLimit characters. //可以看到這是外部迭代while while (length < lengthLimit || count < headCount) { if (!it.moveNext()) return;//這里實際上調(diào)用了WhereIterator中的moveNext函數(shù),經(jīng)過_f函數(shù)處理的moveNext() String next = "${it.current}";//獲取current. parts.add(next); length += next.length + overhead; count++; } ...}

七、firstWhere和singleWhere和lastWhere

1、介紹

E firstWhere(bool test(E element), {E orElse()})E lastWhere(bool test(E element), {E orElse()})E singleWhere(bool test(E element), {E orElse()})

首先從源碼聲明結(jié)構(gòu)上來看,firstWhere、lastWhere和singleWhere是一樣,它們都是接收兩個參數(shù),一個是必需參數(shù):test篩選條件閉包函數(shù),另一個是可選參數(shù):orElse閉包函數(shù)。

但是它們用法卻不同,firstWhere主要是用于篩選順序第一個符合條件的元素,可能存在多個符合條件元素;lastWhere主要是用于篩選順序最后一個符合條件的元素,可能存在多個符合條件元素;singleWhere主要是用于篩選順序唯一一個符合條件的元素,不可能存在多個符合條件元素,存在的話就會拋出異常IterableElementError.tooMany(), 所以使用它的使用需要謹(jǐn)慎注意下

2、使用方式

main() { var numbers = [0, 3, 1, 2, 7, 12, 2, 4]; //注意: 如果沒有找到,執(zhí)行orElse代碼塊,可返回一個指定的默認(rèn)值-1 print(numbers.firstWhere((num) => num == 5, orElse: () => -1)); //注意: 如果沒有找到,執(zhí)行orElse代碼塊,可返回一個指定的默認(rèn)值-1 print(numbers.lastWhere((num) => num == 2, orElse: () => -1)); //注意: 如果沒有找到,執(zhí)行orElse代碼塊,可返回一個指定的默認(rèn)值,前提是集合中只有一個符合條件的元素, 否則就會拋出異常 print(numbers.singleWhere((num) => num == 4, orElse: () => -1)); }

3、源碼解析

//firstWhere E firstWhere(bool test(E element), {E orElse()}) { for (E element in this) {//直接遍歷原集合,只要找到第一個符合條件的元素就直接返回,終止函數(shù) if (test(element)) return element; } if (orElse != null) return orElse();//遍歷完集合后,都沒找到符合條件的元素并且外部傳入了orElse就會觸發(fā)orElse函數(shù) //否則找不到元素,直接拋出異常。所以這里需要注意下,如果不想拋出異常,可能你需要處理下orElse函數(shù)。 throw IterableElementError.noElement(); } //lastWhere E lastWhere(bool test(E element), {E orElse()}) { E result;//定義result來記錄每次符合條件的元素 bool foundMatching = false;//定義一個標(biāo)志位是否找到符合匹配的。 for (E element in this) { if (test(element)) {//每次找到符合條件的元素,都會重置result,所以result記錄了最新的符合條件元素,那么遍歷到最后,它也就是最后一個符合條件的元素 result = element; foundMatching = true;//找到后重置標(biāo)記位 } } if (foundMatching) return result;//如果標(biāo)記位為true直接返回result即可 if (orElse != null) return orElse();//處理orElse函數(shù) //同樣,找不到元素,直接拋出異常。可能你需要處理下orElse函數(shù)。 throw IterableElementError.noElement(); } //singleWhere E singleWhere(bool test(E element), {E orElse()}) { E result; bool foundMatching = false; for (E element in this) { if (test(element)) { if (foundMatching) {//主要注意這里,只要foundMatching為true,說明已經(jīng)找到一個符合條件的元素,如果觸發(fā)這條邏輯分支,說明不止一個元素符合條件就直接拋出IterableElementError.tooMany()異常 throw IterableElementError.tooMany(); } result = element; foundMatching = true; } } if (foundMatching) return result; if (orElse != null) return orElse(); //同樣,找不到元素,直接拋出異常。可能你需要處理下orElse函數(shù)。 throw IterableElementError.noElement(); }

八、join

1、介紹

String join([String separator = ""])

join函數(shù)主要是用于將集合所有元素值轉(zhuǎn)化成字符串,中間用指定的separator連接符連接
可以看到j(luò)oin函數(shù)比較簡單,接收一個separator分隔符的可選參數(shù),可選參數(shù)默認(rèn)值是空字符串,最后返回一個字符串。

2、使用方式

main() { var numbers = [0, 3, 1, 2, 7, 12, 2, 4]; print(numbers.join('-'));//輸出: 0-3-1-2-7-12-2-4}

3、源碼解析

//接收separator可選參數(shù),默認(rèn)值為"" String join([String separator = ""]) { Iterator iterator = this.iterator; if (!iterator.moveNext()) return ""; //創(chuàng)建StringBuffer StringBuffer buffer = StringBuffer(); //如果分隔符為空或空字符串 if (separator == null || separator == "") { //do-while遍歷iterator,然后直接拼接元素 do { buffer.write("${iterator.current}"); } while (iterator.moveNext()); } else { //如果分隔符不為空 //先加入第一個元素 buffer.write("${iterator.current}"); //然后while遍歷iterator while (iterator.moveNext()) { buffer.write(separator);//先拼接分隔符 buffer.write("${iterator.current}");//再拼接元素 } } return buffer.toString();//最后返回最終的字符串。 }

九、take

1、介紹

Iterable take(int count)

take函數(shù)主要是用于截取原集合前count個元素組成的集合,take函數(shù)接收一個count作為函數(shù)參數(shù),最后返回一個泛型參數(shù)為E的Iterable。類似where一樣,take這里也是返回一個惰性的Iterable, 然后對它的iterator進(jìn)行迭代。

takeWhile函數(shù)主要用于

2、使用方式

main() { List numbers = [0, 3, 1, 2, 7, 12, 2, 4]; print(numbers.take(5));//輸出(0, 3, 1, 2, 7)}

3、源碼解析

  • 1、首先, 需要明確一點numbers.take調(diào)用了ListMixin中的take函數(shù),可以看到并沒有直接返回集合前count個元素,而是返回一個TakeIterable惰性Iterable。
Iterable take(int count) { return TakeIterable(this, count); }
  • 2、然后,繼續(xù)深入研究TakeIterable
class TakeIterable extends Iterable { final Iterable _iterable;//存儲原集合 final int _takeCount;//take count factory TakeIterable(Iterable iterable, int takeCount) { ArgumentError.checkNotNull(takeCount, "takeCount"); RangeError.checkNotNegative(takeCount, "takeCount"); if (iterable is EfficientLengthIterable) {//如果原集合是EfficientLengthIterable,就返回創(chuàng)建EfficientLengthTakeIterable return new EfficientLengthTakeIterable(iterable, takeCount); } //否則就返回TakeIterable return new TakeIterable._(iterable, takeCount); } TakeIterable._(this._iterable, this._takeCount);//注意: 這里是返回了TakeIterator,并傳入原集合的iterator以及_takeCount Iterator get iterator { return new TakeIterator(_iterable.iterator, _takeCount); }}
  • 3、然后,繼續(xù)深入研究TakeIterator.
class TakeIterator extends Iterator { final Iterator _iterator;//存儲原集合中的iterator int _remaining;//存儲需要截取的前幾個元素的數(shù)量 TakeIterator(this._iterator, this._remaining) { assert(_remaining >= 0); } bool moveNext() { _remaining--;//通過_remaining作為游標(biāo)控制迭代次數(shù) if (_remaining >= 0) {//如果_remaining大于等于0就會繼續(xù)執(zhí)行moveNext方法 return _iterator.moveNext(); } _remaining = -1; return false;//如果_remaining小于0就返回false,終止外部循環(huán) } E get current { if (_remaining < 0) return null; return _iterator.current; }}
  • 4、所以上述例子中最終還是調(diào)用Iterable的toString方法,方法中會進(jìn)行iterator的迭代,最終會觸發(fā)惰性TakeIterable中的TakeIterator的moveNext方法。

十、takeWhile

1、介紹

Iterable takeWhile(bool test(E value))

takeWhile函數(shù)主要用于依次選擇滿足條件的元素,直到遇到第一個不滿足的元素,并停止選擇。takeWhile函數(shù)接收一個test條件函數(shù)作為函數(shù)參數(shù),然后返回一個惰性的Iterable。

2、使用方式

main() { List numbers = [3, 1, 2, 7, 12, 2, 4]; print(numbers.takeWhile((number) => number > 2).toList());//輸出: [3] 遇到1的時候就不滿足大于2條件就終止篩選。}

3、源碼解析

  • 1、首先,因為numbers是List所以還是調(diào)用ListMixin中的takeWhile函數(shù)
Iterable takeWhile(bool test(E element)) { return TakeWhileIterable(this, test);//可以看到它僅僅返回的是TakeWhileIterable,而不是篩選后符合條件的集合,所以它是惰性。 }
  • 2、然后,繼續(xù)看下TakeWhileIterable的實現(xiàn)
class TakeWhileIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; TakeWhileIterable(this._iterable, this._f); Iterator get iterator { //重寫iterator,創(chuàng)建一個TakeWhileIterator對象并返回。 return new TakeWhileIterator(_iterable.iterator, _f); }}//TakeWhileIteratorclass TakeWhileIterator extends Iterator { final Iterator _iterator; final _ElementPredicate _f; bool _isFinished = false; TakeWhileIterator(this._iterator, this._f); bool moveNext() { if (_isFinished) return false; //原集合_iterator遍歷結(jié)束或者原集合中的當(dāng)前元素current不滿足_f條件,就返回false以此終止外部的迭代。 //進(jìn)一步說明了只有moveNext調(diào)用,才會觸發(fā)_f的執(zhí)行,此時惰性的Iterable才得以執(zhí)行。 if (!_iterator.moveNext() || !_f(_iterator.current)) { _isFinished = true;//迭代結(jié)束重置_isFinished為true return false; } return true; } E get current { if (_isFinished) return null;//如果迭代結(jié)束,還取current就直接返回null了 return _iterator.current; }}

十、skip

1、介紹

Iterable skip(int count)

skip函數(shù)主要是用于跳過原集合前count個元素后,剩下元素組成的集合,skip函數(shù)接收一個count作為函數(shù)參數(shù),最后返回一個泛型參數(shù)為E的Iterable。類似where一樣,skip這里也是返回一個惰性的Iterable, 然后對它的iterator進(jìn)行迭代。

2、使用方式

main() { List numbers = [3, 1, 2, 7, 12, 2, 4]; print(numbers.skip(2).toList());//輸出: [2, 7, 12, 2, 4] 跳過前兩個元素3,1 直接從第3個元素開始 }

3、源碼解析

  • 1、首先,因為numbers是List所以還是調(diào)用ListMixin中的skip函數(shù)
Iterable skip(int count) => SubListIterable(this, count, null);//返回的是一個SubListIterable惰性Iterable,傳入原集合和需要跳過的count大小
  • 2、然后,繼續(xù)看下SubListIterable的實現(xiàn),這里只看下elementAt函數(shù)實現(xiàn)
class SubListIterable extends ListIterable { final Iterable _iterable; // Has efficient length and elementAt. final int _start;//這是傳入的需要skip的count final int _endOrLength;//這里傳入為null ... int get _endIndex { int length = _iterable.length;//獲取原集合長度 if (_endOrLength == null || _endOrLength > length) return length;//_endIndex為原集合長度 return _endOrLength; } int get _startIndex {//主要看下_startIndex的實現(xiàn) int length = _iterable.length;//獲取原集合長度 if (_start > length) return length;//如果skip的count超過集合自身長度,_startIndex為原集合長度 return _start;//否則返回skip的count } E elementAt(int index) { int realIndex = _startIndex + index;//相當(dāng)于把原集合中每個元素原來index,整體向后推了_startIndex,最后獲取真實映射的realIndex if (index < 0 || realIndex >= _endIndex) {//如果realIndex越界就會拋出異常 throw new RangeError.index(index, this, "index"); } return _iterable.elementAt(realIndex);//否則就取對應(yīng)realIndex在原集合中的元素。 } ...}

十一、skipWhile

1、介紹

Iterable skipWhile(bool test(E element))

skipWhile函數(shù)主要用于依次跳過滿足條件的元素,直到遇到第一個不滿足的元素,并停止篩選。skipWhile函數(shù)接收一個test條件函數(shù)作為函數(shù)參數(shù),然后返回一個惰性的Iterable。

2、使用方式

main() { List numbers = [3, 1, 2, 7, 12, 2, 4]; print(numbers.skipWhile((number) => number < 4).toList());//輸出: [7, 12, 2, 4] //因為3、1、2都是滿足小于4的條件,所以直接skip跳過,直到遇到7不符合條件停止篩選,剩下的就是[7, 12, 2, 4]}

3、源碼解析

  • 1、首先,因為numbers是List所以還是調(diào)用ListMixin中的skipWhile函數(shù)
Iterable skipWhile(bool test(E element)) { return SkipWhileIterable(this, test);//可以看到它僅僅返回的是SkipWhileIterable,而不是篩選后符合條件的集合,所以它是惰性的。 }
  • 2、然后,繼續(xù)看下SkipWhileIterable的實現(xiàn)
class SkipWhileIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; SkipWhileIterable(this._iterable, this._f); //重寫iterator,創(chuàng)建一個SkipWhileIterator對象并返回。 Iterator get iterator { return new SkipWhileIterator(_iterable.iterator, _f); }}//SkipWhileIteratorclass SkipWhileIterator extends Iterator { final Iterator _iterator;//存儲原集合的iterator final _ElementPredicate _f;//存儲skipWhile中篩選閉包函數(shù) bool _hasSkipped = false;//判斷是否已經(jīng)跳過元素的標(biāo)識,默認(rèn)為false SkipWhileIterator(this._iterator, this._f);//重寫moveNext函數(shù) bool moveNext() { if (!_hasSkipped) {//如果是最開始第一次沒有跳過任何元素 _hasSkipped = true;//然后重置標(biāo)識為true,表示已經(jīng)進(jìn)行了第一次跳過元素的操作 while (_iterator.moveNext()) {//迭代原集合中的iterator if (!_f(_iterator.current)) return true;//只要找到符合條件的元素,就略過迭代下一個元素,不符合條件就直接返回true終止當(dāng)前moveNext函數(shù),而此時外部迭代循環(huán)正式從當(dāng)前元素開始迭代, } } return _iterator.moveNext();//那么遇到第一個不符合條件元素之后所有元素就會通過_iterator.moveNext()正常返回 } E get current => _iterator.current;}

十二、follwedBy

1、介紹

Iterable followedBy(Iterable other)

followedBy函數(shù)主要用于在原集合后面追加拼接另一個Iterable集合,followedBy函數(shù)接收一個Iterable參數(shù),最后又返回一個Iterable類型的值。

2、使用方式

main() { var languages = ['Kotlin', 'Java', 'Dart', 'Go', 'Python']; print(languages.followedBy(['Swift', 'Rust', 'Ruby', 'C++', 'C#']).toList());//輸出: [Kotlin, Java, Dart, Go, Python, Swift, Rust, Ruby, C++, C#]}

3、源碼解析

  • 1、首先,還是調(diào)用ListMixin中的followedBy函數(shù)
Iterable followedBy(Iterable other) => FollowedByIterable.firstEfficient(this, other);//這里實際上還是返回一個惰性的FollowedByIterable對象,這里使用命名構(gòu)造器firstEfficient創(chuàng)建對象
  • 2、然后,繼續(xù)看下FollowedByIterable中的firstEfficient實現(xiàn)
factory FollowedByIterable.firstEfficient( EfficientLengthIterable first, Iterable second) { if (second is EfficientLengthIterable) {//List肯定是一個EfficientLengthIterable,所以會創(chuàng)建一個EfficientLengthFollowedByIterable,傳入的參數(shù)first是當(dāng)前集合,second是需要在后面拼接的集合 return new EfficientLengthFollowedByIterable(first, second); } return new FollowedByIterable(first, second); }
  • 3、然后,繼續(xù)看下EfficientLengthFollowedByIterable的實現(xiàn),這里只具體看下elementAt函數(shù)的實現(xiàn)
class EfficientLengthFollowedByIterable extends FollowedByIterable implements EfficientLengthIterable { EfficientLengthFollowedByIterable( EfficientLengthIterable first, EfficientLengthIterable second) : super(first, second); ... E elementAt(int index) {//elementAt在迭代過程會調(diào)用 int firstLength = _first.length;//取原集合的長度 if (index < firstLength) return _first.elementAt(index);//如果index小于原集合長度就從原集合中獲取元素 return _second.elementAt(index - firstLength);//否則就通過index - firstLength 計算新的下標(biāo)從拼接的集合中獲取元素。 } ...}

十三、expand

1、介紹

Iterable expand(Iterable f(E element))

expand函數(shù)主要用于將集合中每個元素擴(kuò)展為零個或多個元素或者將多個元素組成二維數(shù)組展開成平鋪一個一維數(shù)組。expand函數(shù)接收一個Iterable f(E element)函數(shù)作為函數(shù)參數(shù)。這個閉包函數(shù)比較特別,特別之處在于f函數(shù)返回的是一個Iterable,那么就意味著可以將原集合中每個元素擴(kuò)展成多個相同元素。注意expand函數(shù)最終還是返回一個惰性的Iterable

2、使用方式

main() { var pair = [ [1, 2], [3, 4] ]; print('flatten list: ${pair.expand((pair) => pair).toList()}');//輸出: flatten list: [1, 2, 3, 4] var inputs = [1, 2, 3]; print('duplicated list: ${inputs.expand((number) => [number, number, number]).toList()}');//輸出: duplicated list: [1, 1, 1, 2, 2, 2, 3, 3, 3]}

3、源碼解析

  • 1、首先還是調(diào)用ListMixin中的expand函數(shù)。
Iterable expand(Iterable f(E element)) => ExpandIterable(this, f);//可以看到這里并沒有直接返回擴(kuò)展的集合,而是創(chuàng)建一個惰性的ExpandIterable對象返回,
  • 2、然后繼續(xù)深入ExpandIterable
typedef Iterable _ExpandFunction(S sourceElement);class ExpandIterable extends Iterable { final Iterable _iterable; final _ExpandFunction _f; ExpandIterable(this._iterable, this._f); Iterator get iterator => new ExpandIterator(_iterable.iterator, _f);//注意: 這里iterator是一個ExpandIterator對象,傳入的是原集合的iterator和expand函數(shù)中閉包函數(shù)參數(shù)_f}//ExpandIterator的實現(xiàn)class ExpandIterator implements Iterator { final Iterator _iterator; final _ExpandFunction _f; //創(chuàng)建一個空的Iterator對象_currentExpansion Iterator _currentExpansion = const EmptyIterator(); T _current; ExpandIterator(this._iterator, this._f); T get current => _current;//重寫current//重寫moveNext函數(shù),只要當(dāng)?shù)臅r候,moveNext執(zhí)行才會觸發(fā)閉包函數(shù)_f執(zhí)行。 bool moveNext() { //如果_currentExpansion返回false終止外部迭代循環(huán) if (_currentExpansion == null) return false; //開始_currentExpansion是一個空的Iterator對象,所以moveNext()為false while (!_currentExpansion.moveNext()) { _current = null; //迭代原集合中的_iterator if (_iterator.moveNext()) { //如果_f拋出異常,先重置_currentExpansion為null, 遇到 if (_currentExpansion == null) return false;就會終止外部迭代 _currentExpansion = null; _currentExpansion = _f(_iterator.current).iterator;//執(zhí)行_f函數(shù) } else { return false; } } _current = _currentExpansion.current; return true; }}

十四、reduce

1、介紹

E reduce(E combine(E previousValue, E element))T fold(T initialValue, T combine(T previousValue, E element))

reduce函數(shù)主要用于集合中元素依次歸納(combine),每次歸納后的結(jié)果會和下一個元素進(jìn)行歸納,它可以用來累加或累乘,具體取決于combine函數(shù)中操作,combine函數(shù)中會回調(diào)上一次歸納后的值和當(dāng)前元素值,reduce提供的是獲取累積迭代結(jié)果的便利條件. fold和reduce幾乎相同,唯一區(qū)別是fold可以指定初始值。 但是需要注意的是,combine函數(shù)返回值的類型必須和集合泛型類型一致。

2、使用方式

main() { List numbers = [3, 1, 2, 7, 12, 2, 4]; print(numbers.reduce((prev, curr) => prev + curr)); //累加 print(numbers.fold(2, (prev, curr) => (prev as int) + curr)); //累加 print(numbers.reduce((prev, curr) => prev + curr) / numbers.length); //求平均數(shù) print(numbers.fold(2, (prev, curr) => (prev as int) + curr) / numbers.length); //求平均數(shù) print(numbers.reduce((prev, curr) => prev * curr)); //累乘 print(numbers.fold(2, (prev, curr) => (prev as int) * curr)); //累乘 var strList = ['a', 'b', 'c']; print(strList.reduce((prev, curr) => '$prev*$curr')); //拼接字符串 print(strList.fold('e', (prev, curr) => '$prev*$curr')); //拼接字符串}

3、源碼解析

E reduce(E combine(E previousValue, E element)) { int length = this.length; if (length == 0) throw IterableElementError.noElement(); E value = this[0];//初始值默認(rèn)取第一個 for (int i = 1; i < length; i++) {//從第二個開始遍歷 value = combine(value, this[i]);//combine回調(diào)value值和當(dāng)前元素值,然后把combine的結(jié)果歸納到value上,依次處理。 if (length != this.length) { throw ConcurrentModificationError(this);//注意: 在操作過程中不允許刪除和添加元素否則就會出現(xiàn)ConcurrentModificationError } } return value; } T fold(T initialValue, T combine(T previousValue, E element)) { var value = initialValue;//和reduce唯一區(qū)別在于這里value初始值是外部指定的 int length = this.length; for (int i = 0; i < length; i++) { value = combine(value, this[i]); if (length != this.length) { throw ConcurrentModificationError(this); } } return value; }

十五、elementAt

1、介紹

E elementAt(int index)

elementAt函數(shù)用于獲取對應(yīng)index下標(biāo)的元素,傳入一個index參數(shù),返回對應(yīng)泛型類型E的元素。

2、使用方式

main() { print(numbers.elementAt(3));//elementAt一般不會直接使用,更多是使用[],運(yùn)算符重載的方式間接使用。 }

3、源碼解析

E elementAt(int index) { ArgumentError.checkNotNull(index, "index"); RangeError.checkNotNegative(index, "index"); int elementIndex = 0; //for-in遍歷原集合,找到對應(yīng)elementIndex元素并返回 for (E element in this) { if (index == elementIndex) return element; elementIndex++; } //找不到拋出RangeError throw RangeError.index(index, this, "index", null, elementIndex); }

總結(jié)

到這里,有關(guān)dart中集合操作符函數(shù)相關(guān)內(nèi)容就結(jié)束了,關(guān)于集合操作符函數(shù)使用在Flutter中開發(fā)非常有幫助,特別在處理集合數(shù)據(jù)中,可以讓你的代碼實現(xiàn)更優(yōu)雅,不要再是一上來就for循環(huán)直接開干,雖然也能實現(xiàn),但是如果能適當(dāng)使用操作符函數(shù),將會使代碼更加簡潔。歡迎繼續(xù)關(guān)注,下一篇Dart中的函數(shù)的使用…

總結(jié)

以上是生活随笔為你收集整理的kotlin 添加第一个 集合_Flutter开发必学Dart语法篇之集合操作符函数与源码分析...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。