ZetCode

Dart Iterable

最后修改于 2025 年 4 月 4 日

在 Dart 中,Iterable 是一个基本接口,用于表示可以顺序访问的元素集合。它提供了强大的方法来处理和转换集合。

Iterable 默认是惰性的,这意味着操作仅在需要时计算。Dart 中的许多集合,如 List 和 Set,都实现了 Iterable 接口。

基本 Iterable 操作

最常见的 Iterable 操作包括映射(mapping)、过滤(filtering)和归约(reducing)。这些构成了 Dart 中集合处理的基础。

main.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。

main.dart
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。

main.dart
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,用于复杂的集合处理。

main.dart
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 默认是惰性的,这意味着操作仅在需要时计算。这可以提高大型集合的性能。

main.dart
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]

最佳实践

来源

Dart Iterable 文档

本教程涵盖了 Dart 的 Iterable 接口,并通过实际示例展示了其强大的集合处理能力。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面有十多年的经验。

列出 所有 Dart 教程