Benutzerdefinierte Iteratoren
Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 33 von 65.
Python lässt eine Klasse sich mit magischen Methoden wie __len__, __getitem__, __contains__ und __iter__ wie eine Liste verhalten. Godot hat virtuelle Methoden nur für eine dieser Aufgaben: die for-Schleife. Drei Methoden sorgen dafür, dass for item in my_object: funktioniert:
_iter_init(iter)wird einmal vor dem ersten Durchlauf ausgeführt. Sie setzt die Startposition und gibttruezurück, wenn es ein erstes Element gibt._iter_get(position)gibt das Element an der aktuellen Position zurück, und die Schleifenvariable erhält diesen Wert._iter_next(iter)wird vor jedem weiteren Durchlauf ausgeführt. Sie geht zur nächsten Position und gibtfalsezurück, wenn es keine weiteren Elemente gibt, wodurch die Schleife beendet wird.
# 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 ist ein Array mit einem Slot, das Godot für jede Schleife erstellt. iter[0] enthält die Position dieser Schleife, und Godot übergibt seinen Wert an _iter_get(). Ein Team funktioniert jetzt in einer for-Schleife:
var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
print(member) # Ada, dann BoSpeichere die Position in iter[0], nicht in einer Member-Variable wie _position. Jede Schleife erhält ihr eigenes iter, sodass zwei Schleifen über dasselbe Team einander nicht stören, selbst wenn eine innerhalb der anderen liegt. Mit einer Member-Variable würde die innere Schleife die Position der äußeren Schleife verändern.
Für die übrigen Listenaufgaben gibt es keine virtuelle Methode: len(team) und team[0] sind Fehler. Schreibe gewöhnliche Methoden mit Namen wie bei Array, etwa size(), get_at(index) und has(member). Prüfe die Mitgliedschaft nicht mit in: "Ada" in team prüft, ob Team eine Eigenschaft oder Methode namens Ada hat, also ist das Ergebnis false.
Aufgabe
EinfachSchreibe die Klasse Bookshelf in bookshelf.gd. Sie speichert die Titel in _titles und fasst höchstens _capacity Bücher:
add(title)fügt den Titel hinzu und gibttruezurück oder gibtfalsezurück, ohne ihn hinzuzufügen, wenn das Regal voll ist oder den Titel bereits enthält.size()gibt die Anzahl der Bücher zurück, undhas(title), ob der Titel im Regal steht.get_at(index)gibt den Titel an diesem Index zurück oder einen leeren String, wenn der Index außerhalb des Regals liegt._iter_init(),_iter_next()und_iter_get()ermöglichen einerfor-Schleife, die Titel in der Reihenfolge durchzugehen, in der sie hinzugefügt wurden.
Der bereitgestellte Code liest die Kapazität, die Anzahl der Titel und jeweils einen Titel pro Zeile ein und gibt die Titel aus, die nicht hinzugefügt werden konnten. Er gibt die Anzahl der Bücher aus, listet sie mit einer for-Schleife über das Regal auf, liest dann einen weiteren Titel ein und gibt aus, ob das Regal ihn enthält, sowie das letzte Buch. Bei einer Kapazität von 3, den Titeln Dune, Emma, Dune, Ulysses, Hamlet und der Suche nach Emma gibt es Folgendes aus:
Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: UlyssesDein Code gehört in bookshelf.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.
Probier es selbst
extends Node
func _ready():
# Vorgegebener Ein-/Ausgabecode: unverändert lassen
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))
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort selfMethodenEigenschaftenKonstruktor (_init)Wiederholung – Einfacher Taschenrechner4Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypisierungAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner2Klassenattribute
Instanz- vs. statische VariablenStatische FunktionenProperty-SetterProperty-GetterPrivat nach KonventionWiederholung – Bankkontenverwaltung5Kapselung
Öffentliche und private MemberValidierung mit SetternInformationsverbergenSchreibgeschützte EigenschaftenRückblick – System zur Schülerverwaltung8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungInnere KlassenNodes als KomponentenRefCounted vs. NodeEnums in Klassen11Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungVererbungskettenTypprüfungen mit isWiederholung – Mitarbeiterhierarchie6Spezielle Methoden
Einführung in virtuelle MethodenDie _to_string-MethodeBenutzerdefinierte IteratorenRückblick – Benutzerdefinierte Liste9Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBeobachter-MusterStrategie-Muster12Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungÜbe selbstständig: Online-GDScript-Compiler