为什么公司的网站打不开,网站如何申请微信支付接口,沈阳建设工程信息网 采购甲方都在中项网,邢台地区网站建设简述:在上一篇文章中#xff0c;我们全面地分析了常用集合的使用以及集合部分源码的分析。那么这一节讲点更实用的内容#xff0c;绝对可以提高你的Flutter开发效率的函数#xff0c;那就是集合中常用的操作符函数。这次说的内容的比较简单就是怎么用#xff0c;以及源码内…简述:在上一篇文章中我们全面地分析了常用集合的使用以及集合部分源码的分析。那么这一节讲点更实用的内容绝对可以提高你的Flutter开发效率的函数那就是集合中常用的操作符函数。这次说的内容的比较简单就是怎么用以及源码内部是怎么实现的。一、Iterable在dart中几乎所有集合拥有的操作符函数(例如: map、every、where、reduce等)都是因为继承或者实现了Iterable。1、Iterable类关系图二、forEach1、介绍 void forEach(void f(E element))forEach在dart中用于遍历和迭代集合也是dart中操作集合最常用的方法之一。接收一个f(E element)函数作为参数返回值类型为空void.2、使用方式main() { var languages [Dart, Kotlin, Java, Javascript, Go, Python, Swift]; languages.forEach((language) print(The language is $language));//由于只有一个表达式所以可以直接使用箭头函数。 languages.forEach((language){ if(language Dart || language Kotlin) { print(My favorite language is $language); } });} 3、源码解析 void forEach(void f(E element)) { //可以看到在forEach内部实际上就是利用for-in迭代每迭代一次就执行一次f函数 //并把当前element回调出去 for (E element in this) f(element); }三、map1、介绍Iterable map(T f(E e))map函数主要用于集合中元素的映射也可以映射转化成其他类型的元素。可以看到map接收一个T f(E e)函数作为参数最后返回一个泛型参数为T的Iterable。实际上是返回了带有元素的一个新的惰性Iterable, 然后通过迭代的时候对每个元素都调用f函数。注意: f函数是一个接收泛型参数为E的元素,然后返回一个泛型参数为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内部本质是一个_GrowableList, 我们都知道_GrowableList是继承了ListBase,然后ListBase又mixin with ListMixin.所以languages.map函数调用就是调用ListMixin中的map函数实际上还是相当于调用了自身的成员函数map.以上面的例子为例1、首先需要明确一点languages内部本质是一个_GrowableList, 我们都知道_GrowableList是继承了ListBase,然后ListBase又mixin with ListMixin.所以languages.map函数调用就是调用ListMixin中的map函数实际上还是相当于调用了自身的成员函数map.pragma(vm:entry-point)class _GrowableList extends ListBase {//_GrowableList是继承了ListBase ...}abstract class ListBase extends Object with ListMixin {//ListBase mixin with ListMixin ...}2、然后可以看到ListMixin实际上实现了List,然后List继承了EfficientLengthIterable最后EfficientLengthIterable继承Iterable所以最终的map函数来自于Iterable但是具体的实现定义在ListMinxin中。abstract class ListMixin implements List { ... //可以看到这里是直接返回一个MappedListIterable它是一个惰性Iterable Iterable map(T f(E element)) MappedListIterable(this, f); ... }3、为什么是惰性的呢可以看到它并不是直接返回转化后的集合而是返回一个带有值的MappedListIterable的如果不执行elementAt方法是不会触发执行map传入的f函数, 所以它是惰性的。class MappedListIterable extends ListIterable { final Iterable _source;//_source存储了所携带的原集合 final _Transformation _f;//_f函数存储了map函数传入的闭包 MappedListIterable(this._source, this._f); int get length _source.length; //注意: 只有elementAt函数执行的时候才会触发执行_f方法然后通过_source的elementAt函数取得原集合中的元素 //最后针对_source中的每个元素执行_f函数处理。 T elementAt(int index) _f(_source.elementAt(index));}4、一般不会单独使用map函数因为单独使用map的函数时仅仅返回的是惰性的MappedListIterable。由上面的源码可知仅仅在elementAt调用的时候才会触发map中的闭包。所以我们一般使用完map后会配合toList()、toSet()函数或者触发elementAt函数的函数(例如这里的join)一起使用。languages.map((language) develop language is ${language}).toList();//toList()方法调用才会真正去执行map中的闭包。languages.map((language) develop language is ${language}).toSet();//toSet()方法调用才会真正去执行map中的闭包。languages.map((language) develop language is ${language}).join(---);//join()方法调用才会真正去执行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]实际上是运算符重载了[]最终就是调用了elementAt函数这里才会真正的触发map中的闭包 } return result; }四、any1、介绍 bool any(bool test(E element))any函数主要用于检查是否存在任意一个满足条件的元素只要匹配到第一个就返回true, 如果遍历所有元素都不符合才返回false.any函数接收一个bool test(E element)函数作为参数test函数回调一个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函数的条件就返回true for (int i 0; i length; i) { if (test(this[i])) return true; if (length ! this.length) { throw ConcurrentModificationError(this); } } //遍历完集合后未找到符合条件的集合就返回false return false; }五、every1、介绍bool every(bool test(E element)) every函数主要用于检查是否集合所有元素都满足条件如果都满足就返回true, 只要存在一个不满足条件的就返回false.every函数接收一个bool test(E element)函数作为参数test函数回调一个E类型的element并返回一个bool类型的值。2、使用方式main() { bool isDartAll languages.every((language) language Dart);}3、源码解析 bool every(bool test(E element)) { //利用for-in遍历集合只要找到不符合test函数的条件就返回false. for (E element in this) { if (!test(element)) return false; }//遍历完集合后找到所有元素符合条件就返回true return true; }六、where1、介绍Iterable where(bool test(E element))where函数主要用于过滤符合条件的元素类似Kotlin中的filter的作用最后返回符合条件元素的集合。where函数接收一个bool test(E element)函数作为参数最后返回一个泛型参数为E的Iterable。类似map一样where这里也是返回一个惰性的Iterable, 然后对它的iterator进行迭代对每个元素都执行test方法。2、使用方式main() { List numbers [0, 3, 1, 2, 7, 12, 2, 4]; print(numbers.where((num) num 6));//输出: (7,12) //注意: 这里是print的内容实际上输出的是Iterable的toString方法返回的内容。}3、源码解析1、首先需要明确一点numbers实际上是一个_GrowableList和map的分析原理类似最终还是调用了ListMixin中的where函数。//可以看到这里是直接返回一个WhereIterable对象而不是返回过滤后元素集合所以它返回的Iterable也是惰性的。Iterable where(bool test(E element)) WhereIterable(this, test);2、然后继续深入研究下WhereIterable是如何实现的class WhereIterable extends Iterable { final Iterable _iterable;//传入的原集合 final _ElementPredicate _f;//传入的where函数中闭包参数 WhereIterable(this._iterable, this._f); //注意: 这里WhereIterable的迭代借助了iterator这里是直接创建一个WhereIterator并传入元集合_iterable中的iterator以及过滤操作函数。 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、然后继续深入研究下WhereIterator是如何实现的class WhereIterator extends Iterator { final Iterator _iterator;//存储集合中的iterator对象 final _ElementPredicate _f;//存储where函数传入闭包函数 WhereIterator(this._iterator, this._f); //重写moveNext函数 bool moveNext() { //遍历原集合的_iterator while (_iterator.moveNext()) { //注意: 这里会执行_f函数如果满足条件就会返回true, 不符合条件的直接略过迭代下一个元素 //那么外部迭代时候就可以通过current获得当前元素这样就实现了在原集合基础上过滤拿到符合条件的元素。 if (_f(_iterator.current)) { return true; } } //迭代完_iterator所有元素后返回false,以此来终止外部迭代。 return false; } //重写current的属性方法 E get current _iterator.current;}4、一般在使用的WhereIterator的时候外部肯定还有一层while迭代但是这个WhereIterator比较特殊moveNext()的返回值由where中闭包函数参数返回值决定的符合条件元素moveNext()就返回true,不符合就略过迭代检查下一个元素直至整个集合迭代完毕moveNext()返回false,以此也就终止了外部的迭代循环。5、上面分析WhereIterable是惰性的那它啥时候触发呢? 没错就是在迭代它的iterator时候才会触发以上面例子为例print(numbers.where((num) num 6));//输出: (7,12)最后会调用Iterable的toString方法返回的内容。//看下Iterable的toString方法实现String toString() IterableBase.iterableToShortString(this, (, ));//这就是为啥输出样式是 (7,12)//继续查看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转化成List内部就是通过迭代iterator,以此会触发WhereIterator中的_f函数。 } 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]. 这个函数代码实现比较多这里给出部分代码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;//这里实际上调用了WhereIterator中的moveNext函数经过_f函数处理的moveNext() String next ${it.current};//获取current. parts.add(next); length next.length overhead; count; } ...}七、firstWhere和singleWhere和lastWhere1、介绍E firstWhere(bool test(E element), {E orElse()})E lastWhere(bool test(E element), {E orElse()})E singleWhere(bool test(E element), {E orElse()})首先从源码声明结构上来看firstWhere、lastWhere和singleWhere是一样它们都是接收两个参数一个是必需参数:test筛选条件闭包函数另一个是可选参数:orElse闭包函数。但是它们用法却不同firstWhere主要是用于筛选顺序第一个符合条件的元素可能存在多个符合条件元素lastWhere主要是用于筛选顺序最后一个符合条件的元素可能存在多个符合条件元素singleWhere主要是用于筛选顺序唯一一个符合条件的元素不可能存在多个符合条件元素存在的话就会抛出异常IterableElementError.tooMany() 所以使用它的使用需要谨慎注意下2、使用方式main() { var numbers [0, 3, 1, 2, 7, 12, 2, 4]; //注意: 如果没有找到执行orElse代码块可返回一个指定的默认值-1 print(numbers.firstWhere((num) num 5, orElse: () -1)); //注意: 如果没有找到执行orElse代码块可返回一个指定的默认值-1 print(numbers.lastWhere((num) num 2, orElse: () -1)); //注意: 如果没有找到执行orElse代码块可返回一个指定的默认值前提是集合中只有一个符合条件的元素, 否则就会抛出异常 print(numbers.singleWhere((num) num 4, orElse: () -1)); }3、源码解析 //firstWhere E firstWhere(bool test(E element), {E orElse()}) { for (E element in this) {//直接遍历原集合只要找到第一个符合条件的元素就直接返回终止函数 if (test(element)) return element; } if (orElse ! null) return orElse();//遍历完集合后都没找到符合条件的元素并且外部传入了orElse就会触发orElse函数 //否则找不到元素直接抛出异常。所以这里需要注意下如果不想抛出异常可能你需要处理下orElse函数。 throw IterableElementError.noElement(); } //lastWhere E lastWhere(bool test(E element), {E orElse()}) { E result;//定义result来记录每次符合条件的元素 bool foundMatching false;//定义一个标志位是否找到符合匹配的。 for (E element in this) { if (test(element)) {//每次找到符合条件的元素都会重置result所以result记录了最新的符合条件元素那么遍历到最后它也就是最后一个符合条件的元素 result element; foundMatching true;//找到后重置标记位 } } if (foundMatching) return result;//如果标记位为true直接返回result即可 if (orElse ! null) return orElse();//处理orElse函数 //同样找不到元素直接抛出异常。可能你需要处理下orElse函数。 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,说明已经找到一个符合条件的元素如果触发这条逻辑分支说明不止一个元素符合条件就直接抛出IterableElementError.tooMany()异常 throw IterableElementError.tooMany(); } result element; foundMatching true; } } if (foundMatching) return result; if (orElse ! null) return orElse(); //同样找不到元素直接抛出异常。可能你需要处理下orElse函数。 throw IterableElementError.noElement(); }八、join1、介绍 String join([String separator ])join函数主要是用于将集合所有元素值转化成字符串中间用指定的separator连接符连接。可以看到join函数比较简单接收一个separator分隔符的可选参数可选参数默认值是空字符串最后返回一个字符串。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可选参数默认值为 String join([String separator ]) { Iterator iterator this.iterator; if (!iterator.moveNext()) return ; //创建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();//最后返回最终的字符串。 }九、take1、介绍 Iterable take(int count)take函数主要是用于截取原集合前count个元素组成的集合take函数接收一个count作为函数参数最后返回一个泛型参数为E的Iterable。类似where一样take这里也是返回一个惰性的Iterable, 然后对它的iterator进行迭代。takeWhile函数主要用于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调用了ListMixin中的take函数可以看到并没有直接返回集合前count个元素而是返回一个TakeIterable惰性Iterable。 Iterable take(int count) { return TakeIterable(this, count); }2、然后继续深入研究TakeIterableclass 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就返回创建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、然后继续深入研究TakeIterator.class TakeIterator extends Iterator { final Iterator _iterator;//存储原集合中的iterator int _remaining;//存储需要截取的前几个元素的数量 TakeIterator(this._iterator, this._remaining) { assert(_remaining 0); } bool moveNext() { _remaining--;//通过_remaining作为游标控制迭代次数 if (_remaining 0) {//如果_remaining大于等于0就会继续执行moveNext方法 return _iterator.moveNext(); } _remaining -1; return false;//如果_remaining小于0就返回false,终止外部循环 } E get current { if (_remaining 0) return null; return _iterator.current; }}4、所以上述例子中最终还是调用Iterable的toString方法方法中会进行iterator的迭代最终会触发惰性TakeIterable中的TakeIterator的moveNext方法。十、takeWhile1、介绍 Iterable takeWhile(bool test(E value))takeWhile函数主要用于依次选择满足条件的元素直到遇到第一个不满足的元素并停止选择。takeWhile函数接收一个test条件函数作为函数参数然后返回一个惰性的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所以还是调用ListMixin中的takeWhile函数 Iterable takeWhile(bool test(E element)) { return TakeWhileIterable(this, test);//可以看到它仅仅返回的是TakeWhileIterable而不是筛选后符合条件的集合所以它是惰性。 }2、然后继续看下TakeWhileIterable的实现class TakeWhileIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; TakeWhileIterable(this._iterable, this._f); Iterator get iterator { //重写iterator创建一个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遍历结束或者原集合中的当前元素current不满足_f条件就返回false以此终止外部的迭代。 //进一步说明了只有moveNext调用才会触发_f的执行此时惰性的Iterable才得以执行。 if (!_iterator.moveNext() || !_f(_iterator.current)) { _isFinished true;//迭代结束重置_isFinished为true return false; } return true; } E get current { if (_isFinished) return null;//如果迭代结束还取current就直接返回null了 return _iterator.current; }}十、skip1、介绍 Iterable skip(int count)skip函数主要是用于跳过原集合前count个元素后剩下元素组成的集合skip函数接收一个count作为函数参数最后返回一个泛型参数为E的Iterable。类似where一样skip这里也是返回一个惰性的Iterable, 然后对它的iterator进行迭代。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所以还是调用ListMixin中的skip函数Iterable skip(int count) SubListIterable(this, count, null);//返回的是一个SubListIterable惰性Iterable传入原集合和需要跳过的count大小2、然后继续看下SubListIterable的实现,这里只看下elementAt函数实现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的实现 int length _iterable.length;//获取原集合长度 if (_start length) return length;//如果skip的count超过集合自身长度_startIndex为原集合长度 return _start;//否则返回skip的count } E elementAt(int index) { int realIndex _startIndex index;//相当于把原集合中每个元素原来index,整体向后推了_startIndex,最后获取真实映射的realIndex if (index 0 || realIndex _endIndex) {//如果realIndex越界就会抛出异常 throw new RangeError.index(index, this, index); } return _iterable.elementAt(realIndex);//否则就取对应realIndex在原集合中的元素。 } ...}十一、skipWhile1、介绍 Iterable skipWhile(bool test(E element))skipWhile函数主要用于依次跳过满足条件的元素直到遇到第一个不满足的元素并停止筛选。skipWhile函数接收一个test条件函数作为函数参数然后返回一个惰性的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所以还是调用ListMixin中的skipWhile函数 Iterable skipWhile(bool test(E element)) { return SkipWhileIterable(this, test);//可以看到它仅仅返回的是SkipWhileIterable而不是筛选后符合条件的集合所以它是惰性的。 }2、然后继续看下SkipWhileIterable的实现class SkipWhileIterable extends Iterable { final Iterable _iterable; final _ElementPredicate _f; SkipWhileIterable(this._iterable, this._f); //重写iterator创建一个SkipWhileIterator对象并返回。 Iterator get iterator { return new SkipWhileIterator(_iterable.iterator, _f); }}//SkipWhileIteratorclass SkipWhileIterator extends Iterator { final Iterator _iterator;//存储原集合的iterator final _ElementPredicate _f;//存储skipWhile中筛选闭包函数 bool _hasSkipped false;//判断是否已经跳过元素的标识默认为false SkipWhileIterator(this._iterator, this._f);//重写moveNext函数 bool moveNext() { if (!_hasSkipped) {//如果是最开始第一次没有跳过任何元素 _hasSkipped true;//然后重置标识为true,表示已经进行了第一次跳过元素的操作 while (_iterator.moveNext()) {//迭代原集合中的iterator if (!_f(_iterator.current)) return true;//只要找到符合条件的元素就略过迭代下一个元素不符合条件就直接返回true终止当前moveNext函数而此时外部迭代循环正式从当前元素开始迭代 } } return _iterator.moveNext();//那么遇到第一个不符合条件元素之后所有元素就会通过_iterator.moveNext()正常返回 } E get current _iterator.current;}十二、follwedBy1、介绍Iterable followedBy(Iterable other)followedBy函数主要用于在原集合后面追加拼接另一个Iterable集合followedBy函数接收一个Iterable参数最后又返回一个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、首先还是调用ListMixin中的followedBy函数 Iterable followedBy(Iterable other) FollowedByIterable.firstEfficient(this, other);//这里实际上还是返回一个惰性的FollowedByIterable对象这里使用命名构造器firstEfficient创建对象2、然后继续看下FollowedByIterable中的firstEfficient实现 factory FollowedByIterable.firstEfficient( EfficientLengthIterable first, Iterable second) { if (second is EfficientLengthIterable) {//List肯定是一个EfficientLengthIterable所以会创建一个EfficientLengthFollowedByIterable传入的参数first是当前集合second是需要在后面拼接的集合 return new EfficientLengthFollowedByIterable(first, second); } return new FollowedByIterable(first, second); }3、然后继续看下EfficientLengthFollowedByIterable的实现,这里只具体看下elementAt函数的实现class EfficientLengthFollowedByIterable extends FollowedByIterable implements EfficientLengthIterable { EfficientLengthFollowedByIterable( EfficientLengthIterable first, EfficientLengthIterable second) : super(first, second); ... E elementAt(int index) {//elementAt在迭代过程会调用 int firstLength _first.length;//取原集合的长度 if (index firstLength) return _first.elementAt(index);//如果index小于原集合长度就从原集合中获取元素 return _second.elementAt(index - firstLength);//否则就通过index - firstLength 计算新的下标从拼接的集合中获取元素。 } ...}十三、expand1、介绍Iterable expand(Iterable f(E element)) expand函数主要用于将集合中每个元素扩展为零个或多个元素或者将多个元素组成二维数组展开成平铺一个一维数组。expand函数接收一个Iterable f(E element)函数作为函数参数。这个闭包函数比较特别特别之处在于f函数返回的是一个Iterable,那么就意味着可以将原集合中每个元素扩展成多个相同元素。注意expand函数最终还是返回一个惰性的Iterable2、使用方式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、首先还是调用ListMixin中的expand函数。 Iterable expand(Iterable f(E element)) ExpandIterable(this, f);//可以看到这里并没有直接返回扩展的集合而是创建一个惰性的ExpandIterable对象返回2、然后继续深入ExpandIterabletypedef 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函数中闭包函数参数_f}//ExpandIterator的实现class ExpandIterator implements Iterator { final Iterator _iterator; final _ExpandFunction _f; //创建一个空的Iterator对象_currentExpansion Iterator _currentExpansion const EmptyIterator(); T _current; ExpandIterator(this._iterator, this._f); T get current _current;//重写current//重写moveNext函数只要当迭代的时候moveNext执行才会触发闭包函数_f执行。 bool moveNext() { //如果_currentExpansion返回false终止外部迭代循环 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;//执行_f函数 } else { return false; } } _current _currentExpansion.current; return true; }}十四、reduce1、介绍E reduce(E combine(E previousValue, E element))T fold(T initialValue, T combine(T previousValue, E element))reduce函数主要用于集合中元素依次归纳(combine)每次归纳后的结果会和下一个元素进行归纳它可以用来累加或累乘具体取决于combine函数中操作combine函数中会回调上一次归纳后的值和当前元素值reduce提供的是获取累积迭代结果的便利条件. fold和reduce几乎相同唯一区别是fold可以指定初始值。 但是需要注意的是combine函数返回值的类型必须和集合泛型类型一致。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); //求平均数 print(numbers.fold(2, (prev, curr) (prev as int) curr) / numbers.length); //求平均数 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];//初始值默认取第一个 for (int i 1; i length; i) {//从第二个开始遍历 value combine(value, this[i]);//combine回调value值和当前元素值然后把combine的结果归纳到value上依次处理。 if (length ! this.length) { throw ConcurrentModificationError(this);//注意: 在操作过程中不允许删除和添加元素否则就会出现ConcurrentModificationError } } return value; } T fold(T initialValue, T combine(T previousValue, E element)) { var value initialValue;//和reduce唯一区别在于这里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; }十五、elementAt1、介绍E elementAt(int index)elementAt函数用于获取对应index下标的元素传入一个index参数返回对应泛型类型E的元素。2、使用方式main() { print(numbers.elementAt(3));//elementAt一般不会直接使用更多是使用[]运算符重载的方式间接使用。 }3、源码解析 E elementAt(int index) { ArgumentError.checkNotNull(index, index); RangeError.checkNotNegative(index, index); int elementIndex 0; //for-in遍历原集合找到对应elementIndex元素并返回 for (E element in this) { if (index elementIndex) return element; elementIndex; } //找不到抛出RangeError throw RangeError.index(index, this, index, null, elementIndex); }总结到这里有关dart中集合操作符函数相关内容就结束了关于集合操作符函数使用在Flutter中开发非常有帮助特别在处理集合数据中可以让你的代码实现更优雅不要再是一上来就for循环直接开干虽然也能实现但是如果能适当使用操作符函数将会使代码更加简洁。欢迎继续关注下一篇Dart中的函数的使用…