Dart语法篇之集合的使用与源码解析(二)

本文详细介绍了Dart中的集合类型,包括List、Set、Map的使用、构造函数及源码分析。重点讨论了dart:core与dart:collection包中的实现区别,以及List的external关键字、Set的不重复特性、Map的LinkedHashMap实现。此外,还探讨了Queue、LinkedList、HashMap、SplayTreeMap的区别以及命名构造函数from和of的适用场景。
摘要由CSDN通过智能技术生成

简述:

我们将继续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.f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熊喵先生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值