Dart语法篇之集合操作符函数与源码分析(三)

简述:

在上一篇文章中,我们全面地分析了常用集合的使用以及集合部分源码的分析。那么这一节讲点更实用的内容,绝对可以提高你的Flutter开发效率的函数,那就是集合中常用的操作符函数。这次说的内容的比较简单就是怎么用,以及源码内部是怎么实现的。

一、Iterable<E>

在dart中几乎所有集合拥有的操作符函数(例如: map、every、where、reduce等)都是因为继承或者实现了Iterable

1、Iterable类关系图

2、Iterable类方法图

二、forEach

1、介绍
  void forEach(void f(E element))

forEach在dart中用于遍历和迭代集合,也是dart中操作集合最常用的方法之一。接收一个f(E element)函数作为参数,返回值类型为空void.

2、使用方式
main() {
  var languages = <String>['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);
  }

三、map

1、介绍
Iterable<T> map<T>(T f(E e))

map函数主要用于集合中元素的映射,也可以映射转化成其他类型的元素。可以看到map接收一个T f(E e)函数作为参数,最后返回一个泛型参数为TIterable。实际上是返回了带有元素的一个新的惰性Iterable, 然后通过迭代的时候,对每个元素都调用f函数。注意: f函数是一个接收泛型参数为E的元素,然后返回一个泛型参数为T的元素,这就是map可以将原集合中每个元素映射成其他类型元素的原因。

2、使用方式
main() {
  var languages = <String>['Dart', 'Kotlin', 'Java', 'Javascript', 'Go', 'Python', 'Swift'];
  print(languages.map((language) => 'develop language is ${language}').join('---'));    
}
3、源码解析

以上面的例子为例,

  • 1、首先,需要明确一点,languages内部本质是一个_GrowableList<T>, 我们都知道_GrowableList<T>是继承了ListBase<T>,然后ListBase<E>又mixin with ListMixin<E>.所以languages.map函数调用就是调用ListMixin<E>中的map函数,实际上还是相当于调用了自身的成员函数map.

@pragma("vm:entry-point")
class _GrowableList<T> extends ListBase<T> {//_GrowableList<T>是继承了ListBase<T>
    ...
}

abstract class ListBase<E> extends Object with ListMixin<E> {//ListBase mixin with ListMixin<E>
    ...
}
  • 2、然后可以看到ListMixin<E>实际上实现了List<E>,然后List<E>继承了EfficientLengthIterable<E>,最后EfficientLengthIterable<E>继承Iterable<E>,所以最终的map函数来自于Iterable<E>但是具体的实现定义在ListMinxin<E>中。
abstract class ListMixin<E> implements List<E> {
    ...
     //可以看到这里是直接返回一个MappedListIterable,它是一个惰性Iterable
     Iterable<T> map<T>(T f(E element)) => MappedListIterable<E, T>(this, f);
    ... 
}
  • 3、为什么是惰性的呢,可以看到它并不是直接返回转化后的集合,而是返回一个带有值的MappedListIterable的,如果不执行elementAt方法,是不会触发执行map传入的f函数, 所以它是惰性的。
class MappedListIterable<S, T> extends ListIterable<T> {
  final Iterable<S> _source;//_source存储了所携带的原集合
  final _Transformation<S, T> _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<E> toList({bool growable = true}) {
    List<E> result;
    if (growable) {
      result = <E>[]..length = length;
    } else {
      result = List<E>(length);
    }
    for (int i = 0; i < length; i++) {
      result[i] = this[i];//注意: 这里的this[i]实际上是运算符重载了[],最终就是调用了elementAt函数,这里才会真正的触发map中的闭包,
    }
    return result;
  }

四、any

1、介绍
 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;
  }

五、every

1、介绍
bool every(bool test(E element)) 

every函数主要用于检查是否集合所有元素都满足条件,如果都满足就返回true, 只要存在一个不满足条件的就返回false.
every函数接收一个bool test(E elem

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊喵先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值