是什么
Iterable<T> 表示可迭代的一系列元素(像一个“可以遍历”的序列)。
List、Set 都实现了 Iterable。
Iterable 的方法(map、where、expand 等)返回惰性 Iterable,只有在真正迭代时才会计算(比如 for-in、toList()、forEach())。
Iterable 是同步集合(与用于异步事件序列的 Stream 不同)。
常见方法
汇总表
| 分类 | 方法 | 作用 | 示例 |
|---|---|---|---|
| 变换 (Transform) | map(f) |
把每个元素映射成新值,返回惰性 Iterable |
[1,2,3].map((e)=>e*2).toList() → [2,4,6] |
expand(f) |
每个元素映射为一个 Iterable,然后扁平化 |
[[1,2],[3]].expand((e)=>e).toList() → [1,2,3] |
|
whereType<T>() |
只保留指定类型的元素 | [1,'a',2].whereType<int>().toList() → [1,2] |
|
| 过滤/切片 (Filter/Slice) | where(cond) |
按条件筛选 | [1,2,3,4].where((e)=>e.isOdd).toList() → [1,3] |
take(n) |
取前 n 个 | [1,2,3,4].take(2).toList() → [1,2] |
|
skip(n) |
跳过前 n 个 | [1,2,3,4].skip(2).toList() → [3,4] |
|
takeWhile(cond) |
从头开始,满足条件时取 | [1,2,3,0,4].takeWhile((e)=>e>0).toList() → [1,2,3] |
|
skipWhile(cond) |
从头开始,满足条件时跳过 | [1,2,-1,3].skipWhile((e)=>e>0).toList() → [-1,3] |
|
followedBy(iterable) |
连接两个 Iterable | [1,2].followedBy([3,4]).toList() → [1,2,3,4] |
|
| 查找/访问 (Find/Access) | first |
第一个元素 | [1,2,3].first → 1 |
last |
最后一个元素 | [1,2,3].last → 3 |
|
single |
要求只有一个元素时取它,否则抛异常 | [42].single → 42 |
|
firstWhere(cond) |
找到第一个满足条件的元素 | [1,2,3].firstWhere((e)=>e>1) → 2 |
|
| 判定 (Predicate) | any(cond) |
只要有一个满足条件就返回 true | [1,2,3].any((e)=>e>2) → true |
every(cond) |
所有都满足条件才返回 true | [1,2,3].every((e)=>e>0) → true |
|
contains(val) |
是否包含某个值 | [1,2,3].contains(2) → true |
|
| 聚合 (Aggregate) | reduce(f) |
把所有元素两两合并 | [1,2,3].reduce((a,b)=>a+b) → 6 |
fold(init,f) |
从初始值开始累积 | [1,2,3].fold(10,(a,b)=>a+b) → 16 |
|
join([sep]) |
拼接为字符串 | ['a','b','c'].join('-') → "a-b-c" |
|
| 转换/终止 (Convert /Terminate) |
toList() |
转为 List(立即求值) | [1,2,3].map((e)=>e*2).toList() → [2,4,6] |
toSet() |
转为 Set(去重) | [1,2,2,3].toSet() → {1,2,3} |
|
forEach(f) |
遍历执行副作用(非惰性,立即执行) | [1,2].forEach(print) → 输出 1\n2 |
|
cast<T>() |
转换元素类型(运行时检查) | ['a','b'].cast<String>() |
变换(transform)
map((e) => ...):把每个元素转换成新值,返回Iterable。expand((e) => Iterable):把每个元素映射成一个Iterable,并扁平化。
var nums = [1,2,3];
var doubled = nums.map((n) => n * 2); // Iterable<int>
print(doubled.toList()); // [2,4,6]
var nested = [ [1,2], [3] ];
var flat = nested.expand((x) => x);
print(flat.toList()); // [1,2,3]
过滤(filter / slicing)
where((e) => cond):筛选符合条件的元素:take(n)/skip(n):取前几个、跳过前几个。takeWhile/skipWhile:按条件取/跳。
var odds = [1, 2, 3, 4].where((n) => n.isOdd);
print(odds.toList()); // [1, 3]
print([1,2,3,4,5].take(3).toList()); // [1,2,3]
print([1,2,3,4,5].skip(2).toList()); // [3,4,5]
print([1,2,3,0,4].takeWhile((e)=> e > 0).toList()); // [1,2,3]
print([1,2,-1,3,4].skipWhile((e)=> e > 0).toList()); // [-1,3,4]
查找 / 判定
first / last / single:取元素
single:要求只有一个元素时取它,否则抛异常
firstWhere(cond):找到第一个满足条件的元素
any :只要有一个满足条件就返回 true
every:所有都满足条件才返回 true
contains:包含检测。
print([10,20,30].first); // 10
print([10,20,30].last); // 30
print([42].single); // 42
print([1,2,3,4].firstWhere((n)=>n>2)); // 3
print([1,2,3].any((n)=>n>2)); // true
print([1,2,3].every((n)=>n>0)); // true
print([1,2,3].contains(2)); // true
聚合 / 归约
reduce((a,b)=>...):两两合并,需至少一个元素。
fold(initial, (acc,e)=>...):从初始值开始累积。
join(separator):拼接为字符串。
print([1,2,3,4].reduce((a,b)=>a+b)); // 10
print([1,2,3].fold(10, (a,b)=>a+b)); // 16 (10+1+2+3)
print(['a','b','c'].join('-')); // a-b-c
转换 / 终止
toList()/toSet():有限并立即求值,生成集合。forEach((e)=>...):迭代副作用(终止操作)。length:注意:对非List的Iterable,length可能需要遍历一次(O(n))。
var list = [1,2,2,3].toList(); // [1,2,2,3]
var set = [1,2,2,3].toSet(); // {1,2,3}
[1,2,3].forEach((e)=>print("num=$e"));
// 输出:
// num=1
// num=2
// num=3
print([1,2,3].length); // 3
惰性(lazy)示例
var it = [1,2,3].map((e) {
print('map $e');
return e * 2;
});
print('created'); // 这里不会 print map ...
for (var v in it) {
print('value $v');
}
输出顺序会显示 map 1、value 2 … —— 映射函数直到迭代时才执行。
toList() 会立刻触发全部计算并把结果缓存到内存:
var list = it.toList(); // 此处全部执行并返回 List
自定义 Iterable
Iterator<T> 有两个主要成员:bool moveNext() 和 T get current。
yield
用 sync\* + yield(最简便) —— 返回 Iterable,且是惰性的:
Iterable<int> range(int start, int end) sync* {
for (int i = start; i < end; i++) {
yield i;
}
}
(实际开发中 sync* 更常用也更简洁。)
无限序列(lazy 的实用场景)
使用 sync* 你可以写出无限序列(注意在消费端要限制):
Iterable<int> naturals() sync* {
int i = 0;
while (true) yield i++;
}
var firstTen = naturals().take(10).toList(); // 安全地只取 10 个
实现 Iterable / Iterator
实现 Iterable / Iterator(更底层) 或 使用 IterableBase / IterableMixin(dart:collection)简化实现:
class Range extends Iterable<int> {
final int start, end;
Range(this.start, this.end);
@override
Iterator<int> get iterator => _RangeIterator(start, end);
}
class _RangeIterator implements Iterator<int> {
final int _end;
int _current;
_RangeIterator(this._current, this._end);
@override
int get current => _current;
@override
bool moveNext() {
if (_current < _end) {
_current++;
return true;
}
return false;
}
}