可迭代集合
本教程教您如何使用實現 Iterable 類的集合——例如 List 和 Set。可迭代物件是各種 Dart 應用程式的基本構建塊,您可能已經在不知不覺中使用了它們。本教程將幫助您充分利用它們。
使用嵌入式 DartPad 編輯器,您可以透過執行示例程式碼和完成練習來測試您的知識。
要充分利用本教程,您應該具備 Dart 語法的基礎知識。
本教程涵蓋以下內容
- 如何讀取 Iterable 的元素。
- 如何檢查 Iterable 的元素是否滿足某個條件。
- 如何過濾 Iterable 的內容。
- 如何將 Iterable 的內容對映到不同的值。
完成本教程的預計時間:60 分鐘。
本教程中的練習包含部分完成的程式碼片段。您可以使用 DartPad 透過完成程式碼並點選 Run 按鈕來測試您的知識。不要編輯 main 函式中或其下方的測試程式碼。
如果您需要幫助,請在每個練習後展開 Hint 或 Solution 下拉選單。
什麼是集合?
#集合是一個表示一組物件的物件,這些物件被稱為元素。可迭代物件是一種集合。
集合可以為空,也可以包含許多元素。根據目的,集合可以有不同的結構和實現。以下是一些最常見的集合型別
什麼是 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<int> iterable = [1, 2, 3];
int value = iterable.elementAt(1);根據可迭代物件的實現和專案數量,elementAt 可能具有線性複雜性且開銷較大。如果您計劃重複訪問特定專案,請考慮對可迭代物件呼叫 .toList() 一次將其轉換為列表,然後使用 [] 運算子。
final items = veryLargeIterable().toList();
final tenthItem = items[9];
final hundredthItem = items[99];
final thousandthItem = items[999];
final lastItem = items.last;繼續下一節,瞭解更多關於如何訪問 Iterable 元素的資訊。
讀取元素
#您可以使用 for-in 迴圈按順序讀取可迭代物件的元素。
示例:使用 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'];
// You can find with a simple expression:
var foundItem1 = items.firstWhere((item) => item.length > 5);
print(foundItem1);
// Or try using a function block:
var foundItem2 = items.firstWhere((item) {
return item.length > 5;
});
print(foundItem2);
// Or even pass in a function reference:
var foundItem3 = items.firstWhere(predicate);
print(foundItem3);
// You can also use an `orElse` function in case no value is found!
var foundItem4 = items.firstWhere(
(item) => item.length > 10,
orElse: () => 'None!',
);
print(foundItem4);
}
在此示例中,您可以看到編寫謂詞的三種不同方式
- 作為表示式:測試程式碼只有一行,使用箭頭語法(
=>)。 - 作為程式碼塊:測試程式碼在括號內有多行,並有一個返回語句。
- 作為函式:測試程式碼在一個外部函式中,作為引數傳遞給
firstWhere()方法。
沒有對錯之分。使用最適合您的方式,並使您的程式碼更易於閱讀和理解。
最後一個示例呼叫 firstWhere(),帶有一個可選的命名引數 orElse,當找不到元素時,它提供一個替代值。在這種情況下,返回文字 'None!',因為沒有元素滿足提供的條件。
練習:練習編寫測試謂詞
#以下練習是一個失敗的單元測試,其中包含一個部分完成的程式碼片段。您的任務是透過編寫程式碼使測試透過來完成練習。您無需實現 main()。
此練習介紹了 singleWhere()。此方法的工作方式類似於 firstWhere(),但在此情況下,它期望 Iterable 中只有一個元素滿足謂詞。如果 Iterable 中有多個元素或沒有元素滿足謂詞條件,則該方法將丟擲 StateError 異常。
您的目標是為 singleWhere() 實現滿足以下條件的謂詞
- 元素包含字元
'a'。 - 元素以字元
'M'開頭。
測試資料中的所有元素都是 字串;您可以檢視類文件以獲取幫助。
// Implement the predicate of singleWhere
// with the following conditions
// * The element contains the character `'a'`
// * The element starts with the character `'M'`
String singleWhere(Iterable<String> items) {
return items.singleWhere(TODO('Implement the outlined predicate.'));
}
// The following code is used to provide feedback on your solution.
// There is no need to read or modify it.
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('At least one item contains "a"');
}
if (items.every((item) => item.length >= 5)) {
print('All items have length >= 5');
}
}
在該示例中,any() 驗證至少一個元素是否包含字元 a,而 every() 驗證所有元素的長度是否大於或等於 5。
執行程式碼後,嘗試更改 any() 的謂詞,使其返回 false
if (items.any((item) => item.contains('Z'))) {
print('At least one item contains "Z"');
} else {
print('No item contains "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: Implement the anyUserUnder18 function.
}
bool everyUserOver13(Iterable<User> users) {
// TODO: Implement the everyUserOver13 function.
}
class User {
final String name;
final int age;
User(
this.name,
this.age,
);
}
// The following code is used to provide feedback on your solution.
// There is no need to read or modify it.
void main() {
final users = [
User('Alice', 21),
User('Bob', 17),
User('Claire', 52),
User('David', 14),
];
try {
final out = anyUserUnder18(users);
if (!out) {
print('Looks like `anyUserUnder18` is wrong. Keep trying!');
return;
}
} on UnimplementedError {
print(
'Tried running `anyUserUnder18`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print('Tried running `anyUserUnder18`, but received an exception: $e');
return;
}
try {
// with only one user older than 18, should be false
final out = anyUserUnder18([User('Alice', 21)]);
if (out) {
print(
'Looks like `anyUserUnder18` is wrong. What if all users are over 18?');
return;
}
} on UnimplementedError {
print(
'Tried running `anyUserUnder18`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `anyUserUnder18([User("Alice", 21)])`, '
'but received an exception: $e',
);
return;
}
try {
final out = everyUserOver13(users);
if (!out) {
print(
'Looks like `everyUserOver13` is wrong. '
'There are no users under 13!',
);
return;
}
} on UnimplementedError {
print(
'Tried running `everyUserOver13`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `everyUserOver13`, '
'but received an exception: $e',
);
return;
}
try {
final out = everyUserOver13([User('Dan', 12)]);
if (out) {
print(
'Looks like `everyUserOver13` is wrong. '
'There is at least one user under 13!',
);
return;
}
} on UnimplementedError {
print(
'Tried running `everyUserOver13`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `everyUserOver13([User(\'Dan\', 12)])`, '
'but received an exception: $e',
);
return;
}
print('Success. All tests passed!');
}
提示
請記住利用 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 is even');
}示例:使用 where()
#執行此示例以瞭解 where() 如何與其他方法(如 any())一起使用。
void main() {
var evenNumbers = const [1, -2, 3, 42].where((number) => number.isEven);
for (final number in evenNumbers) {
print('$number is even.');
}
if (evenNumbers.any((number) => number.isNegative)) {
print('evenNumbers contains negative numbers.');
}
// If no element satisfies the predicate, the output is empty.
var largeNumbers = evenNumbers.where((number) => number > 1000);
if (largeNumbers.isEmpty) {
print('largeNumbers is empty!');
}
}
在此示例中,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('Numbers until 0: $numbersUntilZero');
var numbersStartingAtZero = numbers.skipWhile((number) => number != 0);
print('Numbers starting at 0: $numbersStartingAtZero');
}
在此示例中,takeWhile() 返回一個 Iterable,其中包含滿足謂詞的元素之前的所有元素。另一方面,skipWhile() 返回一個 Iterable,其中包含滿足謂詞的第一個元素之後(包括該元素)的所有元素。
執行示例後,更改 takeWhile() 以獲取元素,直到它達到第一個負數。
var numbersUntilNegative = numbers.takeWhile(
(number) => !number.isNegative,
);請注意,條件 number.isNegative 被 ! 否定。
練習:從列表中過濾元素
#以下練習提供了使用 where() 方法與先前練習中的 User 類的實踐。
使用 where() 實現兩個函式
- 第 1 部分:實現
filterOutUnder21()。- 返回一個包含所有 21 歲或以上使用者的
Iterable。
- 返回一個包含所有 21 歲或以上使用者的
- 第 2 部分:實現
findShortNamed()。- 返回一個包含所有名字長度為 3 或更短的使用者的
Iterable。
- 返回一個包含所有名字長度為 3 或更短的使用者的
Iterable<User> filterOutUnder21(Iterable<User> users) {
// TODO: Implement the filterOutUnder21 function.
}
Iterable<User> findShortNamed(Iterable<User> users) {
// TODO: Implement the findShortNamed function.
}
class User {
final String name;
final int age;
User(
this.name,
this.age,
);
}
// The following code is used to provide feedback on your solution.
// There is no need to read or modify it.
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(
'Looks like `filterOutUnder21` is wrong, there are '
'exactly two users with age under 21. Keep trying!',
);
return;
}
} on UnimplementedError {
print(
'Tried running `filterOutUnder21`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `filterOutUnder21`, '
'but received an exception: ${e.runtimeType}',
);
return;
}
try {
final out = findShortNamed(users);
if (out.any((user) => user.name.length > 3) || out.length != 2) {
print(
'Looks like `findShortNamed` is wrong, there are '
'exactly two users with a three letter name. Keep trying!',
);
return;
}
} on UnimplementedError {
print(
'Tried running `findShortNamed`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `findShortNamed`, '
'but received an exception: ${e.runtimeType}',
);
return;
}
print('Success. All tests passed!');
}
提示
請記住利用 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() 方法對映 Iterables 可以讓您對每個元素應用一個函式,將每個元素替換為一個新元素。
Iterable<int> output = numbers.map((number) => number * 10);在此示例中,Iterable 數字的每個元素都乘以 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('Numbers: $numbersByTwo');
}
練習:對映到不同的型別
#在前面的示例中,您將 Iterable 的元素乘以 2。該操作的輸入和輸出都是 int 型別的 Iterable。
在此練習中,您的程式碼接受一個 User 型別的 Iterable,您需要返回一個包含每個使用者姓名和年齡的字串的 Iterable。
Iterable 中的每個字串都必須遵循此格式:'{name} is {age}'——例如 'Alice is 21'。
Iterable<String> getNameAndAges(Iterable<User> users) {
// TODO: Implement the getNameAndAges function.
}
class User {
final String name;
final int age;
User(
this.name,
this.age,
);
}
// The following code is used to provide feedback on your solution.
// There is no need to read or modify it.
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(
'Looks like `getNameAndAges` is wrong. Keep trying! '
'The output was: $out',
);
return;
}
} on UnimplementedError {
print(
'Tried running `getNameAndAges`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print('Tried running the function, but received an exception: $e');
return;
}
print('Success. All tests passed!');
}
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。 - 結合提供的函式
isValidEmailAddress()使用any()方法。
第 3 部分:實現 validEmailAddresses()。
- 編寫函式
validEmailAddresses(),它接受一個Iterable<EmailAddress>,並返回另一個只包含有效地址的Iterable<EmailAddress>。 - 使用
where()方法過濾Iterable<EmailAddress>。 - 使用提供的函式
isValidEmailAddress()來評估EmailAddress是否有效。
Iterable<EmailAddress> parseEmailAddresses(Iterable<String> strings) {
// TODO: Implement the parseEmailAddresses function.
}
bool anyInvalidEmailAddress(Iterable<EmailAddress> emails) {
// TODO: Implement the anyInvalidEmailAddress function.
}
Iterable<EmailAddress> validEmailAddresses(Iterable<EmailAddress> emails) {
// TODO: Implement the validEmailAddresses function.
}
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}';
}
// The following code is used to provide feedback on your solution.
// There is no need to read or modify it.
void main() {
const input = [
'ali@gmail.com',
'bobgmail.com',
'cal@gmail.com',
];
const correctInput = ['dash@gmail.com', 'sparky@gmail.com'];
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(
'Tried running `parseEmailAddresses`, but received an empty list.',
);
return;
}
if (!_listEquals(emails.toList(), [
EmailAddress('ali@gmail.com'),
EmailAddress('bobgmail.com'),
EmailAddress('cal@gmail.com'),
])) {
print('Looks like `parseEmailAddresses` is wrong. Keep trying!');
return;
}
} on UnimplementedError {
print(
'Tried running `parseEmailAddresses`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `parseEmailAddresses`, '
'but received an exception: $e',
);
return;
}
try {
final out = anyInvalidEmailAddress(emails);
if (!out) {
print(
'Looks like `anyInvalidEmailAddress` is wrong. Keep trying! '
'The result should be false with at least one invalid address.',
);
return;
}
final falseOut = anyInvalidEmailAddress(correctEmails);
if (falseOut) {
print(
'Looks like `anyInvalidEmailAddress` is wrong. Keep trying! '
'The result should be false with all valid addresses.',
);
return;
}
} on UnimplementedError {
print(
'Tried running `anyInvalidEmailAddress`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running `anyInvalidEmailAddress`, but received an exception: $e');
return;
}
try {
final valid = validEmailAddresses(emails);
if (emails.isEmpty) {
print('Tried running `validEmailAddresses`, but received an empty list.');
return;
}
if (!_listEquals(valid.toList(), [
EmailAddress('ali@gmail.com'),
EmailAddress('cal@gmail.com'),
])) {
print('Looks like `validEmailAddresses` is wrong. Keep trying!');
return;
}
} on UnimplementedError {
print(
'Tried running `validEmailAddresses`, but received an error. '
'Did you implement the function?',
);
return;
} catch (e) {
print(
'Tried running the `validEmailAddresses`, '
'but received an exception: $e',
);
return;
}
print('Success. All tests passed!');
}
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 參考以瞭解本教程未涵蓋的方法。