Dart Iterator
最后修改日期:2025 年 6 月 7 日
在 Dart 中,Iterator 接口作为一种基本的机制,用于按顺序访问集合中的元素。它在 Dart 的迭代系统中起着至关重要的作用,允许开发人员高效地遍历列表、集合、映射和其他可迭代结构。
Iterator 接口定义了两个基本方法:
-
moveNext()- 将迭代器推进到集合中的下一个元素。如果还有下一个元素,它返回true;如果已到达集合末尾,则返回false。 -
current- 检索迭代的当前元素。如果尚未调用moveNext()或迭代已完成,则此属性返回null。
在 Dart 中,大多数集合都实现了 Iterable 接口,该接口通过 iterator 属性提供迭代器。这允许使用 for-in 循环、forEach() 方法或通过手动管理迭代器(使用 moveNext() 和 current)轻松地迭代元素。
Iterator 接口在处理异步或自定义集合时特别有用,在这些情况下,显式控制迭代可以优化性能和内存使用。通过实现 Iterator,开发人员可以为专用数据结构创建定制的遍历逻辑。
基本 Iterator 用法
此示例展示了手动使用迭代器的基本方法。
void main() {
var numbers = [1, 2, 3, 4, 5];
var iterator = numbers.iterator;
while (iterator.moveNext()) {
print(iterator.current);
}
}
我们从列表中创建一个迭代器,并使用 moveNext() 来遍历元素。current 属性获取当前元素。这就是 for-in 循环的内部工作原理。
$ dart main.dart 1 2 3 4 5
自定义 Iterator 实现
此示例演示了创建一个实现 Iterator 的自定义类。
class Countdown implements Iterator<int> {
int _current = 5;
@override
int get current => _current;
@override
bool moveNext() {
if (_current > 0) {
_current--;
return true;
}
return false;
}
}
void main() {
var countdown = Countdown();
while (countdown.moveNext()) {
print(countdown.current);
}
}
我们用从 5 到 0 的倒计时实现了 Iterator 接口。moveNext() 会递减 _current 直到它达到 0。current getter 返回该值。
$ dart main.dart 4 3 2 1 0
带 Iterator 的 Iterable
此示例展示了如何创建一个提供迭代器的自定义 Iterable 类。
class FibonacciSequence implements Iterable<int> {
final int count;
FibonacciSequence(this.count);
@override
Iterator<int> get iterator => _FibonacciIterator(count);
}
class _FibonacciIterator implements Iterator<int> {
final int count;
int _current = 0;
int _next = 1;
int _position = 0;
_FibonacciIterator(this.count);
@override
int get current => _current;
@override
bool moveNext() {
if (_position < count) {
var newNext = _current + _next;
_current = _next;
_next = newNext;
_position++;
return true;
}
return false;
}
}
void main() {
var fib = FibonacciSequence(7);
for (var num in fib) {
print(num);
}
}
我们创建了一个斐波那契数列生成器。Iterable 提供了一个生成数字的迭代器。这允许该类在 for-in 循环中使用。
$ dart main.dart 1 1 2 3 5 8 13
带复杂对象的 Iterator
此示例展示了如何将迭代器与自定义对象集合一起使用。
import 'dart:core';
class Book {
final String title;
final String author;
Book(this.title, this.author);
@override
String toString() => '$title by $author';
}
class Library extends Iterable<Book> {
final List<Book> _books = [];
void add(Book book) => _books.add(book);
@override
Iterator<Book> get iterator => _books.iterator;
}
void main() {
var library = Library();
library.add(Book('Dart in Action', 'Manning'));
library.add(Book('Flutter in Action', 'Manning'));
library.add(Book('Effective Dart', 'Google'));
for (var book in library) {
print(book);
}
}
我们创建了一个包含 Books 并扩展了 Iterable 的 Library 类。迭代器来自底层的 List。这种模式在集合类中很常见。
$ dart main.dart Dart in Action by Manning Flutter in Action by Manning Effective Dart by Google
在下一个示例中,我们将学习如何扩展 IterableMixin 接口来创建自定义的可迭代集合。
import 'dart:collection';
class Book {
final String title;
final String author;
Book(this.title, this.author);
@override
String toString() => '$title by $author';
}
class Library extends IterableMixin<Book> {
final List<Book> _books = [];
void add(Book book) => _books.add(book);
@override
Iterator<Book> get iterator => _books.iterator;
}
void main() {
final library = Library()
..add(Book('Dart in Action', 'Manning'))
..add(Book('Flutter in Action', 'Manning'))
..add(Book('Effective Dart', 'Google'));
// Using iterator directly
final iterator = library.iterator;
while (iterator.moveNext()) {
print(iterator.current);
}
// Using Iterable methods
print('\nBooks with "Action":');
library
.where((book) => book.title.contains('Action'))
.forEach(print);
print('\nBook titles:');
library
.map((book) => book.title.toUpperCase())
.forEach(print);
}
我们创建了一个扩展了 IterableMixin 的 Library 类,该类提供了 Iterable 接口的默认实现。这使我们能够专注于实现 iterator 方法。该示例演示了如何直接使用迭代器,还展示了用于过滤和转换元素的常见 Iterable 方法,如 where 和 map。
下一个示例展示了如何在不依赖 IterableMixin 的情况下完全满足 Iterable 接口。
class Book {
final String title;
final String author;
Book(this.title, this.author);
@override
String toString() => '$title by $author';
}
class Library implements Iterable<Book> {
final List<Book> _books = [];
void add(Book book) => _books.add(book);
@override
bool any(bool Function(Book element) test) {
for (var book in _books) {
if (test(book)) return true;
}
return false;
}
@override
Iterable<R> cast<R>() sync* {
for (var book in _books) {
yield book as R;
}
}
@override
bool contains(Object? element) => _books.contains(element);
@override
Book elementAt(int index) => _books.elementAt(index);
@override
bool every(bool Function(Book element) test) {
for (var book in _books) {
if (!test(book)) return false;
}
return true;
}
@override
Iterable<T> expand<T>(Iterable<T> Function(Book element) f) sync* {
for (var book in _books) {
yield* f(book);
}
}
@override
Book get first => _books.first;
@override
Book firstWhere(bool Function(Book element) test, {Book Function()? orElse}) {
for (var book in _books) {
if (test(book)) return book;
}
if (orElse != null) return orElse();
throw StateError('No element');
}
@override
T fold<T>(T initialValue, T Function(T previousValue, Book element) combine) {
var value = initialValue;
for (var book in _books) {
value = combine(value, book);
}
return value;
}
@override
Iterable<Book> followedBy(Iterable<Book> other) sync* {
yield* _books;
yield* other;
}
@override
void forEach(void Function(Book element) f) {
for (var book in _books) {
f(book);
}
}
@override
bool get isEmpty => _books.isEmpty;
@override
bool get isNotEmpty => _books.isNotEmpty;
@override
Iterator<Book> get iterator => _books.iterator;
@override
String join([String separator = '']) => _books.join(separator);
@override
Book get last => _books.last;
@override
Book lastWhere(bool Function(Book element) test, {Book Function()? orElse}) {
for (var i = _books.length - 1; i >= 0; i--) {
if (test(_books[i])) return _books[i];
}
if (orElse != null) return orElse();
throw StateError('No element');
}
@override
int get length => _books.length;
@override
Iterable<T> map<T>(T Function(Book e) f) sync* {
for (var book in _books) {
yield f(book);
}
}
@override
Book reduce(Book Function(Book value, Book element) combine) {
if (_books.isEmpty) throw StateError('No elements');
var value = _books.first;
for (var i = 1; i < _books.length; i++) {
value = combine(value, _books[i]);
}
return value;
}
@override
Book get single {
if (_books.length == 1) return _books.first;
if (_books.isEmpty) throw StateError('No elements');
throw StateError('More than one element');
}
@override
Book singleWhere(bool Function(Book element) test, {Book Function()? orElse}) {
Book? result;
var found = false;
for (var book in _books) {
if (test(book)) {
if (found) throw StateError('More than one element');
result = book;
found = true;
}
}
if (!found) {
if (orElse != null) return orElse();
throw StateError('No element');
}
return result!;
}
@override
Iterable<Book> skip(int count) sync* {
for (var i = count; i < _books.length; i++) {
yield _books[i];
}
}
@override
Iterable<Book> skipWhile(bool Function(Book value) test) sync* {
var skipping = true;
for (var book in _books) {
if (skipping && test(book)) {
continue;
} else {
skipping = false;
yield book;
}
}
}
@override
Iterable<Book> take(int count) sync* {
var taken = 0;
for (var book in _books) {
if (taken++ >= count) break;
yield book;
}
}
@override
Iterable<Book> takeWhile(bool Function(Book value) test) sync* {
for (var book in _books) {
if (!test(book)) break;
yield book;
}
}
@override
List<Book> toList({bool growable = true}) => List<Book>.from(_books, growable: growable);
@override
Set<Book> toSet() => Set<Book>.from(_books);
@override
Iterable<Book> where(bool Function(Book element) test) sync* {
for (var book in _books) {
if (test(book)) yield book;
}
}
@override
Iterable<T> whereType<T>() sync* {
for (var book in _books) {
if (book is T) yield book as T;
}
}
}
void main() {
var library = Library();
library.add(Book('Dart in Action', 'Manning'));
library.add(Book('Flutter in Action', 'Manning'));
library.add(Book('Effective Dart', 'Google'));
for (var book in library) {
print(book);
}
print('\nBooks with "Action":');
for (var book in library.where((b) => b.title.contains('Action'))) {
print(book);
}
}
所有必需的 Iterable 方法都已手动实现。这允许 Library 类像 Dart 中的任何其他可迭代集合一样使用。该示例演示了如何遍历库并根据条件过滤书籍。这种方法提供了对迭代过程的完全控制,并允许自定义行为,同时仍然遵守 Iterable 接口约定。当您需要创建一种自定义集合类型,该类型表现得像标准可迭代对象,但具有特定的要求或优化时,此方法非常有用。
Iterator 工具
此示例演示了 takeWhile 和 skipWhile 等有用的迭代器工具。
void main() {
var numbers = [1, 3, 5, 2, 4, 6, 8, 7];
print('Numbers while odd:');
var oddIterator = numbers.takeWhile((n) => n.isOdd).iterator;
while (oddIterator.moveNext()) {
print(oddIterator.current);
}
print('\nNumbers after first even:');
var afterEven = numbers.skipWhile((n) => n.isOdd).iterator;
while (afterEven.moveNext()) {
print(afterEven.current);
}
}
我们使用 takeWhile 来获取条件失败之前的元素,并使用 skipWhile 来跳过条件失败之前的元素。这些方法返回新的迭代器。
$ dart main.dart Numbers while odd: 1 3 5 Numbers after first even: 2 4 6 8 7
来源
本教程通过实际示例介绍了 Dart 的 Iterator 接口,展示了基本用法、自定义实现和常见模式。
作者
列出 所有 Dart 教程。