简述:
我们将继续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