在看 Flutter 官方的 Flutter Widget of the Week
系列视频时,有一个视频讲 collection 库提供了许多方便的功能,值的从头到晚看一下,网上没搜到什么资料,于是便看下它的 API,试用了一遍。
作为 Dart 官方的库,主要是提供一些操作集合的方法。总体分为三类:封装的类,扩展的方法,顶层的函数。下面先看封装的类。
Delegating
有 DelegatingIterable
、DelegatingList
、DelegatingSet
、DelegatingMap
、DelegatingQueue
。
参数是原始类型的值,有什么用处呢,比如 DelegatingIterable
。
一来可以扩展它,添加了自定义的操作,原来 Iterable 的操作也可以继续用,并且不直接扩展 Iterable,这样普通的 Iterable 没有这些扩展方法,必须是 DelegatingXXX 类型的才可以用这个扩展方法。
二来假如别的地方扩展了 Iterable 了,但是我现在一些地方不想用,用 DelegatingXXX 后,就只能用属于 Iterable 的方法,而用不了别人扩展 Iterable 的方法。
Combined
CombinedIterableView
将多个集合合并成一个,元素类型可以都不一样。
代码语言:dart复制CombinedIterableView civ = const CombinedIterableView([{1,2,3},['a','b','c']]);
print(civ); // (1, 2, 3, a, b, c)
CombinedListView
将多个列表合并成一个列表,元素类型必须一样。
代码语言:dart复制CombinedListView clv = CombinedListView<int>([[1, 2, 3], [5,6,7]]);
print(clv); // [1, 2, 3, 5, 6, 7]
CombinedMapView
将多个 Map 合并成一个。
代码语言:dart复制var map1 = {'a':1,'b':2};
var map2 = {'cd':3, 'de':4, 'fg': 5};
var set = {map1, map2};
CombinedMapView cmv = CombinedMapView(set);
assert(cmv.length == 5);
assert(cmv['cd'] == 3);
Equality
CaseInsensitiveEquality
忽略大小写,判断两个字符串是否相同。
代码语言:dart复制CaseInsensitiveEquality equality = const CaseInsensitiveEquality();
bool equal = equality.equals('abc', 'ABC');
assert(equal);
DeepCollectionEquality
如果是集合,递归往里面去对比。
代码语言:dart复制// 两个不同的内存地址
var list1 = [2];
var list2 = [2];
assert(list1 != list2);
DeepCollectionEquality dce = const DeepCollectionEquality();
bool equal = dce.equals(list1, list2); // true,比较里面的元素
DefaultEquality
使用参数对象的 ==
和 hashcode 来判断。就类似 Java 中重写类的 equals/hashCode 方法后调用 equals 判断两个对象是否相等。
EqualityBy
每个元素使用构造方法的函数参数的返回值来判断是否相等。
代码语言:dart复制EqualityBy<String, int> eb = EqualityBy((String e)=>e.length);
bool equal = eb.equals('abc', 'def');
assert(equal); // 长度相同,所以是 ture
IdentityEquality
Dart 对象都有一个 identity,底层 identical()
方法判断两个 identity 是否相等,其实就是判断引用是否一样。
IterableEquality/ListEquality/SetEquality/MapEquality
对于集合,相同位置的元素相同为 true。如果 Map,就是键值都相等。
MultiEquality
代码语言:dart复制@override
bool equals(E e1, E e2) {
for (var eq in _equalities) {
if (eq.isValidKey(e1)) return eq.isValidKey(e2) && eq.equals(e1, e2);
}
return false;
}
参数是其它比较器的列表,然后调用 equals,开始遍历这些比较器,只要一个比较器第一个参数通过 isValidKey 判断为 true 时,就用这个比较器了,第二个参数判断是否有效和 equals 作与。
怎么用,可能要自定义子类,修改 isValidKey 的实现。
代码语言:dart复制var equalities = [ // 范型要一样
const DefaultEquality<String>(),
const IdentityEquality<String>(),
const CaseInsensitiveEquality(),
];
MultiEquality me = MultiEquality(equalities);
bool b = me.equals('abc', 'ABC'); // false
Unmodifiable
UnmodifiableListView
不可变 List,但原始 List 可以变,由于同一个引用,原始的变了,它也变了。
代码语言:dart复制final numbers = <int>[10, 20, 30];
final unmodifiableListView = UnmodifiableListView(numbers);
numbers.addAll([40, 50]);
print(numbers);
print(unmodifiableListView); // [10,20,30,40,50]
unmodifiableListView.add(60); // 报错
UnmodifiableSetMixin/UnmodifiableSetView
不可以修改内容的 Set,UnmodifiableSetView 混入了 UnmodifiableSetMixin,UnmodifiableSetMixin 适合其它的 Set,不想让它可变的情况。
代码语言:dart复制final numbers = <int>{10, 20, 30};
final unmodifiableSetView = UnmodifiableSetView(numbers);
numbers.addAll([40, 50]);
print(numbers); // [10,20,30,40,50]
print(unmodifiableSetView); // [10,20,30,40,50]
unmodifiableSetView.add(60); // 报错
UnmodifiableMapView
不可以改变元素的 Map。
代码语言:dart复制final map = {'a':1, 'b':2};
final unmodifiableMapView = UnmodifiableMapView(map);
map['c'] = 3;
print(unmodifiableMapView); // {a: 1, b: 2, c: 3}
unmodifiableMapView['d'] = 4; // 报错
UnmodifiableMapMixin
不是 mixin,是 abstract class,UnmodifiableMapView 并不是它的子类。其它 Map 不允许修改的时候继承它。
Map
CanonicalizedMap
将键用一个函数转换。
代码语言:dart复制// 键长度大于 2 的情况下,变成大写作为键
CanonicalizedMap<String, String, int> c = CanonicalizedMap((String key)=>key.toUpperCase(), isValidKey: (String key)=>key.length>2);
c['a'] = 1; // 长度小于 2,不会被插入
c['cde'] = 2; // 键变成了 CDE
c['cDE'] = 4; // CDE 这个键的值变成了 4
assert(c['CDE']==4);
CanonicalizedMap<String, String, int> c2 = CanonicalizedMap.from({
'a': 1,
'cde': 2,
'cDE': 4
}, (String key)=>key.toUpperCase());
assert(c2.length==2);
EqualityMap/EqualitySet
键的相等性由参数的 Equality 对象的 equals 判断
代码语言:dart复制EqualityMap map = EqualityMap(const CaseInsensitiveEquality());
EqualitySet set = EqualitySet(EqualityBy<String, String>((String e)=>e.toUpperCase()));
MapKeySet
把一个 Map 的所有键拿出来放到一个 Set 里。没看出来有什么用处,因为 keys.toSet 结果都一样的。
代码语言:dart复制var map = {'b':1, 'a':2, 'bd': 3, 'ae': 4};
map.keys.toSet();
bool b = const SetEquality().equals(map.keys.toSet(), MapKeySet(map));
assert(b);
List
BoolList
值都是布尔值,底层用 Uint32List 存储,节约空间。
代码语言:dart复制// growable true 表示长度自动增长
factory BoolList(int length, {bool fill = false, bool growable = false})
IterableZip
和 Kotlin 类似。
代码语言:dart复制IterableZip iz = IterableZip({[1,2], {'a','b','c'},[true, false, true, false]});
print(iz); // ([1, a, true], [2, b, false])
ListSlice
列表切片,有点类似 Swift 中的字符串切片,和原来的列表共享内存,要变成独立的调用 toList()
。
在使用列表切片时,源列表不得更改长度。,内部有判断这个,如果不一样,操作会报错。
代码语言:dart复制var list = ['a','b','c','d','e','f','g'];
ListSlice<String> slice = ListSlice<String>(list, 2, 5); // [c,d,e],含头不含尾
assert(slice[0]=='c');
slice[0]='h'; // list[2] 变成了 h
// 内部调用 source.setRange(start start, start end, iterable, skipCount);
// 一个奇怪的算法,参数 1,3,就是修改原 List 的 1 1 到 1 3
slice.setRange(1, 3, ['j','k','l','m']);
// slice.insert(5, 'f2h'); // 插入会修改长度,报错
NonGrowableListMixin/NonGrowableListView
从一个 List 搞一个长度不可修改的副本。
代码语言:dart复制var list = [1,2,3,4];
NonGrowableListMixin nglm = NonGrowableListView(list);
// 内容可以修改,但长度不能修改
nglm[1]=5;
NonGrowableListView 混入了 NonGrowableListMixin 的类,所以要创建 List 用这个功能,就直接用 NonGrowableListView。如果有其它的 List 子类,想让它长度不可变,就自己 with NonGrowableListMixin。
Set
UnionSet
和 set.union() 没什么差别,所以作用不大。混入了 UnmodifiableSetMixin,所以不能修改值。
代码语言:dart复制var set1 = {1,2,3};
var set2 = {2,3,4};
bool equal = const SetEquality().equals(set1.union(set2), UnionSet({set1, set2}));
assert(equal);
UnionSetController
内部封装了 UnionSet,UnionSet 不可修改,所以合并后就不能再添加新的 Set 去合并,不能删除之前的一个 Set,而 UnionSetController 可以合并后再添加 Set,也可以从合并的结果中删除一个 Set。
代码语言:dart复制var usc = UnionSetController();
usc.add(set1);
usc.add(set2);
usc.remove(set1);
PriorityQueue/HeapPriorityQueue
优先队列,优先级越高,越在前面,也是变相实现了排序。
代码语言:dart复制PriorityQueue pq = PriorityQueue<String>((a,b)=>b.length-a.length);
hpq.add('abc');
hpq.add('ab');
print(hpq.first);
HeapPriorityQueue 是 PriorityQueue 的子类,基于堆内存,改进了时间复杂度。
代码语言:dart复制HeapPriorityQueue hpq = HeapPriorityQueue<String>((a,b)=>b.length-a.length);
hpq.add('abc'); // 时间复杂度是 O(log(n))
hpq.add('a');
hpq.add('ab');
print(hpq.first); // abc,时间复杂度 O(1)
print(hpq.toList()); // [abc, ab, a],时间复杂度 O(n*log(n))
QueueList
具有 List 和 Queue 的特性,就是 List 的基础上加上 addFirst/addLast/removeFirst/removeLast 的方法。
代码语言:dart复制QueueList<String> ql = QueueList(3); // 初始长度
ql.add('a');
ql.addFirst('b');
print(ql);
QueueList<int> ql2 = QueueList.from([1,2,3,4]);
ql2.addLast(5);
ql2.removeFirst();
print(ql2);