איטרטורים מותאמים אישית
חלק מהיחידה תכנות מונחה עצמים במסלול ה-GDScript של Coddy. שיעור 33 מתוך 65.
Python מאפשרת למחלקה להתנהג כמו רשימה באמצעות שיטות קסם כגון __len__, __getitem__, __contains__ ו-__iter__. ל-Godot יש שיטות וירטואליות רק לאחת מהמשימות האלה: לולאת for. שלוש שיטות מאפשרות ל-for item in my_object: לפעול:
_iter_init(iter)פועלת פעם אחת, לפני הסיבוב הראשון. היא קובעת את מיקום ההתחלה ומחזירהtrueאם יש איבר ראשון._iter_get(position)מחזירה את האיבר במיקום הנוכחי, ומשתנה הלולאה מקבל את הערך הזה._iter_next(iter)פועלת לפני כל סיבוב נוסף. היא עוברת למיקום הבא ומחזירהfalseכשלא נותרו איברים, ובכך מסיימת את הלולאה.
# team.gd
class_name Team
extends RefCounted
var _members: Array[String] = []
func add(member: String) -> void:
_members.append(member)
func _iter_init(iter: Array) -> bool:
iter[0] = 0
return iter[0] < _members.size()
func _iter_next(iter: Array) -> bool:
iter[0] += 1
return iter[0] < _members.size()
func _iter_get(position):
return _members[position]iter הוא מערך עם תא אחד ש-Godot יוצר עבור כל לולאה. iter[0] מכיל את המיקום של אותה לולאה, ו-Godot מעביר את הערך שלו אל _iter_get(). עכשיו Team פועל בלולאת for:
var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
print(member) # Ada, ואז Boשמור את המיקום בתוך iter[0], ולא במשתנה חבר כגון _position. לכל לולאה יש iter משלה, ולכן שתי לולאות שעוברות על אותה קבוצה, אפילו כשאחת מקוננת בתוך השנייה, אינן מפריעות זו לזו. עם משתנה חבר, הלולאה הפנימית הייתה מזיזה את המיקום של הלולאה החיצונית.
לפעולות האחרות של רשימה אין מתודה וירטואלית: len(team) ו־team[0] הן שגיאות. כתבו מתודות רגילות בשמות כמו אלה של Array, כגון size(), get_at(index) ו־has(member). אל תבדקו חברות באמצעות in: "Ada" in team בודק אם ל־Team יש מאפיין או מתודה בשם Ada, ולכן התוצאה היא false.
אתגר
קלכתבו את המחלקה Bookshelf בקובץ bookshelf.gd. היא שומרת את הכותרים ב־_titles ומחזיקה לכל היותר _capacity ספרים:
add(title)מוסיפה את הכותר ומחזירהtrue, או מחזירהfalseבלי להוסיף אותו כאשר המדף מלא או שהכותר כבר נמצא בו.size()מחזירה את מספר הספרים, ו־has(title)מחזירה אם הכותר נמצא במדף.get_at(index)מחזירה את הכותר שנמצא באינדקס הזה, או מחרוזת ריקה כשהאינדקס מחוץ לטווח המדף._iter_init(),_iter_next()ו־_iter_get()מאפשרות ללולאתforלעבור על הכותרים לפי סדר הוספתם.
הקוד שסופק קורא את הקיבולת, את מספר הכותרים וכותר אחד בכל שורה, ומדווח על הכותרים שלא הצליח להוסיף. הוא מדפיס את מספר הספרים, מציג אותם באמצעות לולאת for שעוברת על המדף, ואז קורא כותר נוסף ומדפיס אם הוא נמצא במדף ואת הספר האחרון. עבור קיבולת 3, הכותרים Dune, Emma, Dune, Ulysses, Hamlet והחיפוש Emma, הפלט הוא:
Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: Ulyssesכתבו את הקוד שלכם בקובץ bookshelf.gd. הקובץ main.gd מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.
נסו בעצמכם
extends Node
func _ready():
# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
var shelf := Bookshelf.new(int(OS.read_string_from_stdin()))
var count := int(OS.read_string_from_stdin())
for i in count:
var title := OS.read_string_from_stdin()
if not shelf.add(title):
print("Could not add: " + title)
print("Books: %d" % shelf.size())
var number := 1
for title in shelf:
print("%d. %s" % [number, title])
number += 1
var query := OS.read_string_from_stdin()
print("Has %s: %s" % [query, shelf.has(query)])
print("Last: " + shelf.get_at(shelf.size() - 1))
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםמילת המפתח selfמתודותמאפייניםבנאי (_init)חזרה – מחשבון פשוט2מאפייני מחלקה
משתני מופע לעומת משתנים סטטייםפונקציות סטטיותקובעי מאפייניםמאחזרי מאפייניםפרטיים לפי מוסכמהסיכום – מנהל חשבון בנק5כימוס
איברים ציבוריים ופרטייםאימות באמצעות Settersהסתרת מידעמאפיינים לקריאה בלבדסיכום – מערכת לניהול רשומות תלמידים3ירושה
ירושה בסיסיתמילת המפתח superדריסת מתודותשרשראות ירושהבדיקת טיפוס באמצעות isסיכום – היררכיית עובדים6מתודות מיוחדות
מבוא למתודות וירטואליותהמתודה _to_stringאיטרטורים מותאמים אישיתסיכום – רשימה מותאמת אישיתתרגלו בעצמכם: קומפיילר GDScript אונליין