Iterable 集合
本教程将教你如何使用实现了 Iterable 类(例如 List 和 Set )的集合。Iterable 是各种 Dart 应用程序的基本构建块,你可能已经在使用它们,甚至没有注意到。本教程将帮助你充分利用它们。
使用嵌入式 DartPad 编辑器,你可以通过运行示例代码和完成练习来测试你的知识。
为了充分利用本教程,你应该具备 Dart 语法 的基本知识。
本教程涵盖以下内容:
- 如何读取 Iterable 的元素。
- 如何检查 Iterable 的元素是否满足某个条件。
- 如何过滤 Iterable 的内容。
- 如何将 Iterable 的内容映射到不同的值。
预计完成本教程所需时间:60 分钟。
本教程中的练习包含部分完成的代码片段。你可以使用 DartPad 通过完成代码并点击 运行 按钮来测试你的知识。 不要编辑 main 函数或其下面的测试代码 。
如果需要帮助,请在每个练习之后展开 提示 或 解答 下拉菜单。
什么是集合?
#集合是一个表示一组对象(称为 元素 )的对象。Iterable 是一种集合。
集合可以为空,也可以包含许多元素。根据用途,集合可以具有不同的结构和实现。以下是一些最常见的集合类型:
什么是 Iterable?
#Iterable 是一个可以顺序访问的元素集合。
在 Dart 中, Iterable 是一个抽象类,这意味着你不能直接实例化它。但是,你可以通过创建一个新的 List 或 Set 来创建一个新的 Iterable 。
List 和 Set 都是 Iterable ,因此它们具有与 Iterable 类相同的 方法和属性。
Map 在内部使用不同的数据结构,具体取决于其实现。例如, HashMap 使用哈希表,其中元素(也称为 值 )是使用键获取的。 Map 的元素也可以通过使用 map 的 entries 或 values 属性作为 Iterable 对象读取。
此示例显示了一个 int 的 List ,它也是一个 int 的 Iterable :
Iterable<int> iterable = [1, 2, 3];与 List 的区别在于,对于 Iterable ,你无法保证按索引读取元素的效率。与 List 相反, Iterable 没有 [] 运算符。
例如,考虑以下代码,它是 无效的 :
Iterable<int> iterable = [1, 2, 3];
int value = iterable[1];如果你使用 [] 读取元素,编译器会告诉你运算符 '[]' 没有为 Iterable 类定义,这意味着你不能在这种情况下使用 [index] 。
你可以使用 elementAt() 读取元素,它会遍历 iterable 的元素,直到到达该位置。
Iterable<int> iterable = [1, 2, 3];
int value = iterable.elementAt(1);继续下一节,学习更多关于如何访问 Iterable 元素的内容。
读取元素
#你可以使用 for-in 循环顺序读取 iterable 的元素。
示例:使用 for-in 循环
#以下示例演示如何使用 for-in 循环读取元素。
void main() {
const iterable = ['Salad', 'Popcorn', 'Toast'];
for (final element in iterable) {
print(element);
}
}
示例:使用 first 和 last
#在某些情况下,你只想访问 Iterable 的第一个或最后一个元素。
使用 Iterable 类,你无法直接访问元素,因此你不能调用 iterable[0] 来访问第一个元素。相反,你可以使用 first ,它获取第一个元素。
同样,使用 Iterable 类,你不能使用运算符 [] 来访问最后一个元素,但你可以使用 last 属性。
void main() {
Iterable<String> iterable = const ['Salad', 'Popcorn', 'Toast'];
print('The first element is ${iterable.first}');
print('The last element is ${iterable.last}');
}
在这个例子中,你看到了如何使用 first 和 last 来获取 Iterable 的第一个和最后一个元素。也可以找到满足某个条件的第一个元素。下一节将展示如何使用名为 firstWhere() 的方法来做到这一点。
示例:使用 firstWhere()
#你已经看到你可以顺序访问 Iterable 的元素,并且可以轻松获取第一个或最后一个元素。
现在,你将学习如何使用 firstWhere() 来查找满足特定条件的第一个元素。此方法要求你传递一个 谓词 ,这是一个函数,如果输入满足特定条件,则返回 true。
String element = iterable.firstWhere((element) => element.length > 5);例如,如果你想找到第一个长度超过 5 个字符的 String ,你必须传递一个谓词,当元素大小大于 5 时返回 true。
运行以下示例以查看 firstWhere() 的工作原理。你认为所有函数都会给出相同的结果吗?
bool predicate(String item) {
return item.length > 5;
}
void main() {
const items = ['Salad', 'Popcorn', 'Toast', 'Lasagne'];
// 你可以使用简单的表达式来查找:
var foundItem1 = items.firstWhere((item) => item.length > 5);
print(foundItem1);
// 或者尝试使用函数块:
var foundItem2 = items.firstWhere((item) {
return item.length > 5;
});
print(foundItem2);
// 或者甚至传入函数引用:
var foundItem3 = items.firstWhere(predicate);
print(foundItem3);
// 你也可以在找不到值的情况下使用 `orElse` 函数!
var foundItem4 = items.firstWhere(
(item) => item.length > 10,
orElse: () => 'None!',
);
print(foundItem4);
}
在这个例子中,你可以看到三种不同的编写谓词的方法:
- 作为表达式: 测试代码有一行使用箭头语法 (
=>)。 - 作为块: 测试代码在括号之间有多行和一个 return 语句。
- 作为函数: 测试代码在一个外部函数中,该函数作为参数传递给
firstWhere()方法。
没有正确或错误的方法。使用最适合你的方法,使你的代码更易于阅读和理解。
最后的例子调用 firstWhere() 并使用可选命名参数 orElse ,当找不到元素时提供替代方案。在这种情况下,返回文本 'None!' ,因为没有元素满足提供的条件。
练习:练习编写测试谓词
#以下练习是一个失败的单元测试,其中包含部分完成的代码片段。你的任务是通过编写代码使测试通过来完成练习。你不需要实现 main() 。
本练习介绍了 singleWhere() 。此方法的工作方式类似于 firstWhere() ,但在这种情况下,它只期望 Iterable 中的一个元素满足谓词。如果 Iterable 中的一个以上或没有元素满足谓词条件,则该方法会抛出 StateError 异常。
你的目标是实现 singleWhere() 的谓词,以满足以下条件:
- 元素包含字符
'a'。 - 元素以字符
'M'开头。
测试数据中的所有元素都是 [字符串](https://api.dart.dev/dart-core/String-class.html);你可以查看类文档以获取帮助。
// 使用以下条件实现 singleWhere 的谓词
// * 元素包含字符 `'a'`
// * 元素以字符 `'M'` 开头
String singleWhere(Iterable<String> items) {
return items.singleWhere(TODO('Implement the outlined predicate.'));
}
// 以下代码用于提供解决方案的反馈。
// 无需阅读或修改它。
void main() {
const items = [
'Salad',
'Popcorn',
'Milk',
'Toast',
'Sugar',
'Mozzarella',
'Tomato',
'Egg',
'Water',
];
try {
final str = singleWhere(items);
if (str == 'Mozzarella') {
print('Success. All tests passed!');
} else {
print(
'Tried calling singleWhere, but received $str instead of '
'the expected value \'Mozzarella\'',
);
}
} on StateError catch (stateError) {
print(
'Tried calling singleWhere, but received a StateError: ${stateError.message}. '
'singleWhere will fail if 0 or many elements match the predicate.',
);
} on UnimplementedError {
print(
'Tried running `singleWhere` , but received an error. '
'Did you implement the function?',
);
} catch (e) {
print('Tried calling singleWhere, but received an exception: $e');
}
}
提示
你的解决方案可能会用到 String 类的 contains 和 startsWith 方法。
解答
String singleWhere(Iterable<String> items) {
return items.singleWhere(
(element) => element.startsWith('M') && element.contains('a'));
}检查条件
#在使用 Iterable 时,有时需要验证集合的所有元素是否都满足某个条件。
你可能会尝试使用类似这样的 for-in 循环编写解决方案:
for (final item in items) {
if (item.length < 5) {
return false;
}
}
return true;但是,你可以使用 every() 方法实现相同的功能:
return items.every((item) => item.length >= 5);使用 every() 方法可以使代码更易读、更紧凑且更不容易出错。
示例:使用 any() 和 every()
#Iterable 类提供了两种可用于验证条件的方法:
any():如果至少有一个元素满足条件,则返回 true。every():如果所有元素都满足条件,则返回 true。
运行此练习以查看它们的作用。
void main() {
const items = ['Salad', 'Popcorn', 'Toast'];
if (items.any((item) => item.contains('a'))) {
print('至少有一个项目包含 "a"');
}
if (items.every((item) => item.length >= 5)) {
print('所有项目的长度都 >= 5');
}
}
在示例中, any() 验证至少有一个元素包含字符 a ,而 every() 验证所有元素的长度都大于等于 5。
运行代码后,尝试更改 any() 的谓词使其返回 false:
if (items.any((item) => item.contains('Z'))) {
print('至少有一个项目包含 "Z"');
} else {
print('没有项目包含 "Z"');
}你也可以使用 any() 来验证 Iterable 的任何元素是否都不满足某个条件。
练习:验证 Iterable 是否满足条件
#以下练习提供了使用前面示例中描述的 any() 和 every() 方法的实践。在这种情况下,你使用的是一组用户,由具有成员字段 age 的 User 对象表示。
使用 any() 和 every() 来实现两个函数:
- 第 1 部分:实现
anyUserUnder18()。- 如果至少有一个用户的年龄小于等于 17 岁,则返回
true。
- 如果至少有一个用户的年龄小于等于 17 岁,则返回
- 第 2 部分:实现
everyUserOver13()。- 如果所有用户的年龄都大于等于 14 岁,则返回
true。
- 如果所有用户的年龄都大于等于 14 岁,则返回
bool anyUserUnder18(Iterable<User> users) {
// TODO: 实现 anyUserUnder18 函数。
}
bool everyUserOver13(Iterable<User> users) {
// TODO: 实现 everyUserOver13 函数。
}
class User {
final String name;
final int age;
User(
this.name,
this.age,
);
}
// 以下代码用于提供解决方案的反馈。
// 无需阅读或修改它。
void main() {
final users = [
User('Alice', 21),
User('Bob', 17),
User('Claire', 52),
User('David', 14),
];
try {
final out = anyUserUnder18(users);
if (!out) {
print('看起来 `anyUserUnder18` 是错误的。继续尝试!');
return;
}
} on UnimplementedError {
print(
'尝试运行 `anyUserUnder18` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print('尝试运行 `anyUserUnder18` ,但收到了异常:$e');
return;
}
try {
// 只有一个用户大于 18 岁,应该为 false
final out = anyUserUnder18([User('Alice', 21)]);
if (out) {
print(
'看起来 `anyUserUnder18` 是错误的。如果所有用户都超过 18 岁怎么办?');
return;
}
} on UnimplementedError {
print(
'尝试运行 `anyUserUnder18` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `anyUserUnder18([User("Alice", 21)])` ,'
'但收到了异常:$e',
);
return;
}
try {
final out = everyUserOver13(users);
if (!out) {
print(
'看起来 `everyUserOver13` 是错误的。没有用户小于 13 岁!',
);
return;
}
} on UnimplementedError {
print(
'尝试运行 `everyUserOver13` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `everyUserOver13` ,'
'但收到了异常:$e',
);
return;
}
try {
final out = everyUserOver13([User('Dan', 12)]);
if (out) {
print(
'看起来 `everyUserOver13` 是错误的。至少有一个用户小于 13 岁!',
);
return;
}
} on UnimplementedError {
print(
'尝试运行 `everyUserOver13` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `everyUserOver13([User(\'Dan\', 12)])` ,'
'但收到了异常:$e',
);
return;
}
print('成功。所有测试都通过了!');
}
提示
记住使用 Iterable 类的 any 和 every 方法。 有关使用这些方法的帮助和示例,请参阅 它们之前的讨论 。
解答
bool anyUserUnder18(Iterable<User> users) {
return users.any((user) => user.age < 18);
}
bool everyUserOver13(Iterable<User> users) {
return users.every((user) => user.age > 13);
}过滤
#前面的章节介绍了诸如 firstWhere() 或 singleWhere() 之类的方法,这些方法可以帮助你找到满足特定谓词的元素。
但是,如果要查找满足特定条件的所有元素怎么办?可以使用 where() 方法来实现这一点。
var evenNumbers = numbers.where((number) => number.isEven);在此示例中, numbers 包含一个具有多个 int 值的 Iterable ,而 where() 查找所有偶数。
where() 的输出是另一个 Iterable ,你可以像这样使用它来迭代它或应用其他 Iterable 方法。在下面的示例中, where() 的输出直接用于 for-in 循环中。
var evenNumbers = numbers.where((number) => number.isEven);
for (final number in evenNumbers) {
print('$number 是偶数');
}示例:使用 where()
#运行此示例以了解如何将 where() 与其他方法(如 any() )一起使用。
void main() {
var evenNumbers = const [1, -2, 3, 42].where((number) => number.isEven);
for (final number in evenNumbers) {
print('$number 是偶数。');
}
if (evenNumbers.any((number) => number.isNegative)) {
print('evenNumbers 包含负数。');
}
// 如果没有元素满足谓词,则输出为空。
var largeNumbers = evenNumbers.where((number) => number > 1000);
if (largeNumbers.isEmpty) {
print('largeNumbers 为空!');
}
}
在此示例中, where() 用于查找所有偶数,然后 any() 用于检查结果是否包含负数。
在示例的后面, where() 再次用于查找所有大于 1000 的数字。由于没有这样的数字,因此结果是一个空的 Iterable 。
示例:使用 takeWhile
#takeWhile() 和 skipWhile() 方法也可以帮助你从 Iterable 中过滤元素。
运行此示例以了解如何使用 takeWhile() 和 skipWhile() 来分割包含数字的 Iterable 。
void main() {
const numbers = [1, 3, -2, 0, 4, 5];
var numbersUntilZero = numbers.takeWhile((number) => number != 0);
print('直到 0 的数字:$numbersUntilZero');
var numbersStartingAtZero = numbers.skipWhile((number) => number != 0);
print('从 0 开始的数字:$numbersStartingAtZero');
}
在此示例中, takeWhile() 返回一个 Iterable ,其中包含在满足谓词的元素之前的所有元素。另一方面, skipWhile() 返回一个 Iterable ,其中包含第一个 不 满足谓词的元素之后和包括该元素在内的所有元素。
运行示例后,将 takeWhile() 更改为获取元素,直到到达第一个负数。
var numbersUntilNegative =
numbers.takeWhile((number) => !number.isNegative);请注意,条件 number.isNegative 使用 ! 取反。
练习:从列表中过滤元素
#以下练习提供了使用前面练习中 User 类的 where() 方法的实践。
使用 where() 实现两个函数:
- 第 1 部分:实现
filterOutUnder21()。- 返回一个包含所有年龄大于等于 21 岁的用户的
Iterable。
- 返回一个包含所有年龄大于等于 21 岁的用户的
- 第 2 部分:实现
findShortNamed()。- 返回一个包含所有名称长度小于等于 3 的用户的
Iterable。
- 返回一个包含所有名称长度小于等于 3 的用户的
Iterable<User> filterOutUnder21(Iterable<User> users) {
// TODO: 实现 filterOutUnder21 函数。
}
Iterable<User> findShortNamed(Iterable<User> users) {
// TODO: 实现 findShortNamed 函数。
}
class User {
final String name;
final int age;
User(
this.name,
this.age,
);
}
// 以下代码用于提供解决方案的反馈。
// 无需阅读或修改它。
void main() {
final users = [
User('Alice', 21),
User('Bob', 17),
User('Claire', 52),
User('Dan', 12),
];
try {
final out = filterOutUnder21(users);
if (out.any((user) => user.age < 21) || out.length != 2) {
print(
'看起来 `filterOutUnder21` 是错误的,正好有两个用户的年龄小于 21 岁。继续尝试!',
);
return;
}
} on UnimplementedError {
print(
'尝试运行 `filterOutUnder21` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `filterOutUnder21` ,'
'但收到了异常:${e.runtimeType}',
);
return;
}
try {
final out = findShortNamed(users);
if (out.any((user) => user.name.length > 3) || out.length != 2) {
print(
'看起来 `findShortNamed` 是错误的,正好有两个用户的姓名是三个字母。继续尝试!',
);
return;
}
} on UnimplementedError {
print(
'尝试运行 `findShortNamed` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `findShortNamed` ,'
'但收到了异常:${e.runtimeType}',
);
return;
}
print('成功。所有测试都通过了!');
}
提示
记住要利用 Iterable 类的 where 方法。 有关使用 where 的帮助和示例,请参阅 它之前的讨论 。
解答
Iterable<User> filterOutUnder21(Iterable<User> users) {
return users.where((user) => user.age >= 21);
}
Iterable<User> findShortNamed(Iterable<User> users) {
return users.where((user) => user.name.length <= 3);
}映射
#使用 map() 方法映射 Iterable 使你可以对每个元素应用一个函数,用新元素替换每个元素。
Iterable<int> output = numbers.map((number) => number * 10);在此示例中, Iterable numbers 的每个元素都乘以 10。
你还可以使用 map() 将元素转换为不同的对象——例如,将所有 int 转换为 String ,如下例所示:
Iterable<String> output = numbers.map((number) => number.toString());示例:使用 map 更改元素
#运行此示例以了解如何使用 map() 将 Iterable 的所有元素乘以 2。你认为输出会是什么?
void main() {
var numbersByTwo = const [1, -2, 3, 42].map((number) => number * 2);
print('数字:$numbersByTwo');
}
练习:映射到不同的类型
#在前面的示例中,你将 Iterable 的元素乘以 2。该操作的输入和输出都是 int 的 Iterable 。
在此练习中,你的代码接受一个 User 的 Iterable ,你需要返回一个包含字符串的 Iterable ,这些字符串包含每个用户的姓名和年龄。
Iterable 中的每个字符串都必须遵循以下格式: '{name} is {age}' ——例如 'Alice is 21' 。
Iterable<String> getNameAndAges(Iterable<User> users) {
// TODO: 实现 getNameAndAges 函数。
}
class User {
final String name;
final int age;
User(
this.name,
this.age,
);
}
// 以下代码用于提供解决方案的反馈。
// 无需阅读或修改它。
void main() {
final users = [
User('Alice', 21),
User('Bob', 17),
User('Claire', 52),
];
try {
final out = getNameAndAges(users).toList();
if (!_listEquals(out, ['Alice is 21', 'Bob is 17', 'Claire is 52'])) {
print(
'看起来 `getNameAndAges` 是错误的。继续尝试!输出是:$out',
);
return;
}
} on UnimplementedError {
print(
'尝试运行 `getNameAndAges` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print('尝试运行该函数,但收到了异常:$e');
return;
}
print('成功。所有测试都通过了!');
}
bool _listEquals<T>(List<T>? a, List<T>? b) {
if (a == null) return b == null;
if (b == null || a.length != b.length) return false;
for (var index = 0; index < a.length; index += 1) {
if (a[index] != b[index]) return false;
}
return true;
}
解答
Iterable<String> getNameAndAges(Iterable<User> users) {
return users.map((user) => '${user.name} is ${user.age}');
}练习:综合练习
#现在是时候在一个最后的练习中练习你学到的知识了。
此练习提供 EmailAddress 类,它有一个接收字符串的构造函数。另一个提供的函数是 isValidEmailAddress() ,它测试电子邮件地址是否有效。
| 构造函数/函数 | 类型签名 | 说明 |
|---|---|---|
| EmailAddress() | EmailAddress(String address) | 为指定的地址创建一个 EmailAddress 。 |
| isValidEmailAddress() | bool isValidEmailAddress(EmailAddress) | 如果提供的 EmailAddress 有效,则返回 true 。 |
编写以下代码:
第 1 部分:实现 parseEmailAddresses() 。
- 编写函数
parseEmailAddresses(),它接收一个包含电子邮件地址的Iterable<String>,并返回一个Iterable<EmailAddress>。 - 使用
map()方法将String映射到EmailAddress。 - 使用构造函数
EmailAddress(String)创建EmailAddress对象。
第 2 部分:实现 anyInvalidEmailAddress() 。
- 编写函数
anyInvalidEmailAddress(),它接收一个Iterable<EmailAddress>,如果Iterable中的任何EmailAddress无效,则返回true。 - 将
any()方法与提供的函数isValidEmailAddress()一起使用。
第 3 部分:实现 validEmailAddresses() 。
- 编写函数
validEmailAddresses(),它接收一个Iterable<EmailAddress>并返回另一个Iterable<EmailAddress>,其中只包含有效的地址。 - 使用
where()方法过滤Iterable<EmailAddress>。 - 使用提供的函数
isValidEmailAddress()来评估EmailAddress是否有效。
Iterable<EmailAddress> parseEmailAddresses(Iterable<String> strings) {
// TODO: 实现 parseEmailAddresses 函数。
}
bool anyInvalidEmailAddress(Iterable<EmailAddress> emails) {
// TODO: 实现 anyInvalidEmailAddress 函数。
}
Iterable<EmailAddress> validEmailAddresses(Iterable<EmailAddress> emails) {
// TODO: 实现 validEmailAddresses 函数。
}
class EmailAddress {
final String address;
EmailAddress(this.address);
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is EmailAddress && address == other.address;
@override
int get hashCode => address.hashCode;
@override
String toString() => 'EmailAddress{address: $address}';
}
// 以下代码用于提供解决方案的反馈。
// 无需阅读或修改它。
void main() {
const input = [
'[email protected]',
'bobgmail.com',
'[email protected]',
];
const correctInput = ['[email protected]', '[email protected]'];
bool _listEquals<T>(List<T>? a, List<T>? b) {
if (a == null) return b == null;
if (b == null || a.length != b.length) return false;
for (var index = 0; index < a.length; index += 1) {
if (a[index] != b[index]) return false;
}
return true;
}
final Iterable<EmailAddress> emails;
final Iterable<EmailAddress> correctEmails;
try {
emails = parseEmailAddresses(input);
correctEmails = parseEmailAddresses(correctInput);
if (emails.isEmpty) {
print(
'尝试运行 `parseEmailAddresses` ,但收到了空列表。',
);
return;
}
if (!_listEquals(emails.toList(), [
EmailAddress('[email protected]'),
EmailAddress('bobgmail.com'),
EmailAddress('[email protected]'),
])) {
print('看起来 `parseEmailAddresses` 是错误的。继续尝试!');
return;
}
} on UnimplementedError {
print(
'尝试运行 `parseEmailAddresses` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `parseEmailAddresses` ,'
'但收到了异常:$e',
);
return;
}
try {
final out = anyInvalidEmailAddress(emails);
if (!out) {
print(
'看起来 `anyInvalidEmailAddress` 是错误的。继续尝试!至少有一个无效地址时,结果应该为 false。',
);
return;
}
final falseOut = anyInvalidEmailAddress(correctEmails);
if (falseOut) {
print(
'看起来 `anyInvalidEmailAddress` 是错误的。继续尝试!所有地址都有效时,结果应该为 false。',
);
return;
}
} on UnimplementedError {
print(
'尝试运行 `anyInvalidEmailAddress` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `anyInvalidEmailAddress` ,但收到了异常:$e');
return;
}
try {
final valid = validEmailAddresses(emails);
if (emails.isEmpty) {
print('尝试运行 `validEmailAddresses` ,但收到了空列表。');
return;
}
if (!_listEquals(valid.toList(), [
EmailAddress('[email protected]'),
EmailAddress('[email protected]'),
])) {
print('看起来 `validEmailAddresses` 是错误的。继续尝试!');
return;
}
} on UnimplementedError {
print(
'尝试运行 `validEmailAddresses` ,但收到了错误。你实现这个函数了吗?',
);
return;
} catch (e) {
print(
'尝试运行 `validEmailAddresses` ,'
'但收到了异常:$e',
);
return;
}
print('成功。所有测试都通过了!');
}
bool isValidEmailAddress(EmailAddress email) {
return email.address.contains('@');
}
解答
Iterable<EmailAddress> parseEmailAddresses(Iterable<String> strings) {
return strings.map((s) => EmailAddress(s));
}
bool anyInvalidEmailAddress(Iterable<EmailAddress> emails) {
return emails.any((email) => !isValidEmailAddress(email));
}
Iterable<EmailAddress> validEmailAddresses(Iterable<EmailAddress> emails) {
return emails.where((email) => isValidEmailAddress(email));
}下一步
#恭喜你完成了本教程!如果你想了解更多信息,以下是一些后续建议:
- 使用 DartPad 。
- 尝试另一个 教程 。
- 阅读 Iterable API 参考 以了解本教程未涵盖的方法。
除非另有说明,否则本网站上的文档反映的是 Dart 3.6.0。页面最后更新于 2025-02-05。 查看源代码 或 报告问题.