Dart Iterable
最后修改于 2025 年 4 月 4 日
在 Dart 中,Iterable 是一个基本接口,用于表示可以顺序访问的元素集合。它提供了强大的方法来处理和转换集合。
Iterable 默认是惰性的,这意味着操作仅在需要时计算。Dart 中的许多集合,如 List 和 Set,都实现了 Iterable 接口。
基本 Iterable 操作
最常见的 Iterable 操作包括映射(mapping)、过滤(filtering)和归约(reducing)。这些构成了 Dart 中集合处理的基础。
void main() {
var numbers = [1, 2, 3, 4, 5];
// Mapping
var squares = numbers.map((n) => n * n);
print('Squares: $squares');
// Filtering
var evens = numbers.where((n) => n % 2 == 0);
print('Evens: $evens');
// Reducing
var sum = numbers.reduce((a, b) => a + b);
print('Sum: $sum');
}
这个例子展示了三个基本操作。map 转换每个元素,where 过滤元素,reduce 将元素组合成一个单一的值。
$ dart main.dart Squares: (1, 4, 9, 16, 25) Evens: (2, 4) Sum: 15
链式 Iterable 操作
Iterable 方法可以被链式调用,以创建复杂的处理管道。每个操作都会返回一个新的 Iterable。
void main() {
var words = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
var result = words
.where((word) => word.length > 4)
.map((word) => word.toUpperCase())
.take(3);
print(result);
}
我们过滤出长度大于 4 个字符的单词,将它们转换为大写,并取前 3 个结果。当使用这些值时,操作才会惰性执行。
$ dart main.dart (BANANA, CHERRY, ELDERBERRY)
创建自定义 Iterables
你可以通过实现 Iterable 接口或使用 sync* 生成器函数来创建自定义 Iterables。
Iterable<int> countDown(int from) sync* {
for (int i = from; i >= 0; i--) {
yield i;
}
}
void main() {
var numbers = countDown(5);
print(numbers);
print(numbers.toList());
}
sync* 函数创建一个惰性 Iterable,它会按需生成值。yield 关键字提供序列中的每个值。
$ dart main.dart (5, 4, 3, 2, 1, 0) [5, 4, 3, 2, 1, 0]
高级 Iterable 方法
Iterable 提供了许多高级方法,如 expand、fold 和 any,用于复杂的集合处理。
void main() {
var matrix = [
[1, 2],
[3, 4],
[5, 6]
];
// Flatten matrix
var flattened = matrix.expand((row) => row);
print('Flattened: $flattened');
// Check condition
var hasNegative = flattened.any((n) => n < 0);
print('Has negative: $hasNegative');
// Fold (like reduce but with initial value)
var product = flattened.fold(1, (p, n) => p * n);
print('Product: $product');
}
expand 展平嵌套的集合,any 检查是否任何元素都满足一个条件,而 fold 是 reduce 的一个更灵活的版本,它有一个初始值。
$ dart main.dart Flattened: (1, 2, 3, 4, 5, 6) Has negative: false Product: 720
使用 Iterables 进行惰性求值
Iterables 默认是惰性的,这意味着操作仅在需要时计算。这可以提高大型集合的性能。
Iterable<int> generateNumbers() sync* {
print('Generator started');
for (int i = 1; i <= 5; i++) {
print('Yielding $i');
yield i;
}
}
void main() {
var numbers = generateNumbers()
.map((n) {
print('Mapping $n');
return n * 2;
})
.take(2);
print('Created pipeline');
print('First: ${numbers.first}');
print('ToList: ${numbers.toList()}');
}
这个例子演示了惰性求值。操作仅在实际需要值时执行,正如打印语句所示。
$ dart main.dart Created pipeline Generator started Yielding 1 Mapping 1 First: 2 Yielding 2 Mapping 2 ToList: [2, 4]
最佳实践
- 惰性 vs 立即求值: 当你需要立即求值时,请使用 toList()。
- 方法链: 链式调用操作以实现可读性强的管道。
- 性能: 注意对同一个 Iterable 进行多次迭代。
- 无限 Iterables: 使用 take() 来限制无限序列。
来源
本教程涵盖了 Dart 的 Iterable 接口,并通过实际示例展示了其强大的集合处理能力。
作者
列出 所有 Dart 教程。