集合概述
Dart 中的集合数据类型(Collection)包括 List、Set、Map 和 Queue。
classDiagram
Iterable~E~ <|.. List~E~
Iterable~E~ <|.. Set~E~
Iterable~E~ <|.. Queue~E~
class Iterable{
<<mixin>>
+ Iterator~E~ get iterator
}
<<interface>> List
<<interface>> Set
<<interface>> Queue
Iterator~E~ <-- Iterable~E~
Iterable <-- Map~K,V~
class Iterator {
<<interface>>
+ E get current
+ bool moveNext()
}
class Map{
<<interface>>
+ Iterable~MapEntry<K, V>~ get entries
+ Iterable~K~ get keys
+ Iterable~V~ get values
}
List
List 是一组有序的对象(元素)的集合,可以通过下标(从 0 开始的整数)获取对应位置的元素。
// ex621.dart
void main() {
var letters = ['A', 'B', 'C', 'A'];
assert(4 == letters.length);
assert('A' == letters[0]);
assert('B' == letters[1]);
assert('C' == letters[2]);
print(letters); // Output: [A, B, C, A]
print(letters.toSet()); // Output: {A, B, C}
}
Set
Set 不关心元素的排序顺序,它关注的是元素是否在集合里,Set 中的元素不会重复。
// ex622.dart
void main() {
var letters = {'A', 'B', 'C', 'A'};
assert(3 == letters.length); // 1
print(letters); // 2 Output: {A, B, C}
print(letters.toList()); // 2a Output: [A, B, C]
}
letters的长度为 3 而不是 4;letters包含的 3 个元素即{A, B, C},A只出现了一次。
Queue
Queue 表示队列,它提供了队列两端的添加/移除操作。
// ex623.dart
import 'dart:collection';
void main() {
var q = Queue.of(['A', 'B', 'C']);
print(q); // Output: {A, B, C}
q.addFirst('X');
print(q); // Output: {X, A, B, C}
q.addLast('Y');
print(q); // Output: {X, A, B, C, Y}
q.removeLast();
print(q); // Output: {X, A, B, C}
q.removeFirst();
print(q); // Output: {A, B, C}
}
Map
Map 是键值(key-value)对的集合,它表达了 key 到 value 的映射关系。
// ex624.dart
void main() {
var prices = {'Apple': 1.2, 'Banana': 1.4, 'Cherry': 2.1};
print(prices.runtimeType); // Output: _Map<String, double>
print(prices['Apple']); // Output: 1.2
prices['Apple'] = 1.5;
prices['Damson'] = .5;
print(prices); // Output: {Apple: 1.5, Banana: 1.4, Cherry: 2.1, Damson: 0.5}
print(prices.keys); // Output: (Apple, Banana, Cherry, Damson)
print(prices.values); // Output: (1.5, 1.4, 2.1, 0.5)
print(prices.entries);
// Output: (MapEntry(Apple: 1.5), MapEntry(Banana: 1.4), MapEntry(Cherry: 2.1), MapEntry(Damson: 0.5))
}
集合元素
先以 List 为例,简单说明下集合元素。在以[a, b, ...]这样的语法书写 List 时,其中的a、b等称为元素(elements);每个元素将被求值(evaluated)以产生 0 到多个值(value),这些值随后将被插入到结果 List 中。集合元素分为叶元素(leaf elements)和控制流元素(control flow elements)两类。
// ex633.dart
void main() {
print([1 * 1, 2 * 2, 3 * 3]); // 1 Output: [1, 4, 9]
int? a;
print([1, 2, a, 3]); // 2 Output: [1, 2, null, 3]
print([1, 2, ?a, 3]); // 2a Output: [1, 2, 3]
final arr = [3, 4];
var arr2 = [1, 2, ...arr, 5]; // 3
print('${arr2.runtimeType} $arr2'); // Output: List<int> [1, 2, 3, 4, 5]
List<int>? arr3;
print([1, 2, ...?arr3, 3]); // 4 Output: [1, 2, 3]
}
- 此行代码展示的是表达式元素(Expression elements),它属于叶元素;
- 这行中的
?a是 Null-aware 元素,请与上一行代码进行对比; - 这行中的
...arr乃 Spread 元素; - 这行中的
...?arr3乃 Null-aware Spread 元素。
if 元素
if元素 和 for元素 都是控制流元素。下面的示例展示了if元素的各种用法。
// ex634.dart
void main() {
var present = true;
print([0, if (present) 1, 2, 3]); // 1 Output: [0, 1, 2, 3]
print([0, if (!present) 1, 2, 3]); // 1a Output: [0, 2, 3]
var letter = 'A';
print([
if (letter == 'A') 'apple' else 'orange',
'orange',
]); // 2 Output: [apple, orange]
print([
if (letter == 'A') 'apricot' else if (letter == 'O') 'orange',
'orange',
]); // 3 Output: [apricot, orange]
var data = ['apple', 0.2];
print([
if (data case [var name, var price])
'The price of $name is \$$price'
else
'Error data',
]); // 4 Output: [The price of apple is $0.2]
}
for 元素
如下示例简单展示了for元素的用法。
// ex635.dart
void main() {
var numbers = [for (var i = 2; i <= 8; i += 2) i, 10]; // 1
print(numbers); // Output: [2, 4, 6, 8, 10]
var squares = [for (var n in numbers) n * n]; // 2
print(squares); // Output: [4, 16, 36, 64, 100]
}
嵌套控制流元素
控制流元素可以互相嵌套。
// ex636.dart
void main() {
var evens = [
for (var i = 0; i < 10; i++)
if (i % 2 == 0) i,
];
print(evens); // Output: [0, 2, 4, 6, 8]
var numbers = [
for (var i = 0; i < 10; i++)
if (i % 3 == 0)
for (var j = i; j < i + 3; j++)
if (j < 10) j,
];
print(numbers); // Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}