Menu
Coddy logo textTech

Iterable ו-Iterator

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Dart של Coddy. שיעור 68 מתוך 110.

בכל פעם שמשתמשים בלולאת for-in על List, Set או אוסף אחר, עובדים מאחורי הקלעים עם Iterable ועם Iterator. הבנת המושגים האלה מאפשרת ליצור מחלקות משלך שאפשר לעבור עליהן בלולאה.

Iterable הוא כל אובייקט שיכול להפיק רצף של ערכים. יש לו דרישה מרכזית אחת: getter בשם iterator שמחזיר Iterator. ה-Iterator הוא זה שעובר בפועל בין האיברים, אחד בכל פעם:

var numbers = [1, 2, 3];
var iterator = numbers.iterator;

while (iterator.moveNext()) {
  print(iterator.current);  // 1, אחר כך 2, אחר כך 3
}

המתודה moveNext() מתקדמת לאיבר הבא ומחזירה true אם יש כזה, או false בסיום. המאפיין current נותן לך את האיבר הנוכחי.

כדי להפוך את המחלקה שלך לאיטרטיבית, יש לממש את הממשק Iterable:

class Countdown extends Iterable<int> {
  final int start;
  Countdown(this.start);
  
  @override
  Iterator<int> get iterator => CountdownIterator(start);
}

class CountdownIterator implements Iterator<int> {
  int _current;
  
  CountdownIterator(int start) : _current = start + 1;
  
  @override
  int get current => _current;
  
  @override
  bool moveNext() {
    if (_current > 0) {
      _current--;
      return true;
    }
    return false;
  }
}

void main() {
  for (var n in Countdown(3)) {
    print(n);  // 3, 2, 1, 0
  }
}

כעת Countdown עובד עם לולאות for-in ועם כל המתודות של Iterable, כמו map,‏ where ו-fold. התבנית הזאת חיונית כשיוצרים אוספים מותאמים אישית שמשתלבים בצורה חלקה במערכת האקולוגית של האוספים ב-Dart.

challenge icon

אתגר

קל

בואו נבנה מחולל טווחים מותאם אישית שאפשר לעבור עליו באמצעות לולאת for-in! תיצרו מחלקות Iterable ו-Iterator משלכם כדי ליצור רצף של מספרים בטווח מוגדר.

תארגנו את הקוד שלכם בשני קבצים:

  • range.dart: צרו שתי מחלקות שפועלות יחד כדי להפיק רצף של מספרים:
    • מחלקת RangeIterator שמממשת את Iterator<int>. היא צריכה לעקוב אחר המיקום הנוכחי ולדעת מתי לעצור. האיטרטור מתחיל לפני האיבר הראשון, לכן יש לקרוא ל-moveNext() לפני שניגשים ל-current.
    • מחלקת Range שמרחיבה את Iterable<int>. היא מקבלת ערכי start ו-end בבנאי שלה ומספקת getter בשם iterator שמחזיר RangeIterator.
    הטווח צריך לכלול גם את start וגם את end. לדוגמה, Range(1, 5) צריך להפיק: 1, 2, 3, 4, 5.
  • main.dart: ייבאו את קובץ הטווח שלכם והדגימו את האיטרביל המותאם אישית:
    • צרו Range(1, 5) והשתמשו בלולאת for-in כדי להדפיס כל מספר בשורה נפרדת
    • הדפיסו שורה ריקה
    • צרו Range(10, 13) והשתמשו בשיטת map כדי להכפיל כל ערך, ואז הדפיסו את הרשימה שהתקבלה

מכיוון שמחלקת Range שלכם מרחיבה את Iterable, היא מקבלת אוטומטית גישה לכל שיטות האוסף העוצמתיות, כמו map, where ו-fold — זה היופי במימוש הממשק Iterable!

הפלט הצפוי:

1
2
3
4
5

[20, 22, 24, 26]

נסו בעצמכם

import 'range.dart';

void main() {
  // TODO: צרו Range(1, 5) והשתמשו בלולאת for-in כדי להדפיס כל מספר
  
  
  // TODO: הדפיסו שורה ריקה
  
  
  // TODO: צרו Range(10, 13), השתמשו ב-map כדי להכפיל כל ערך ב-2, והדפיסו את הרשימה
  
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Dart אונליין