Własne iteratory
Część sekcji Programowanie obiektowe ścieżki GDScript w Coddy. Lekcja 33 z 65.
Python sprawia, że klasa zachowuje się jak lista dzięki specjalnym metodom, takim jak __len__, __getitem__, __contains__ i __iter__. Godot udostępnia metody wirtualne tylko dla jednego z tych zastosowań: pętli for. Trzy metody sprawiają, że działa zapis for item in my_object::
_iter_init(iter)uruchamia się raz, przed pierwszym przebiegiem. Ustawia pozycję początkową i zwracatrue, jeśli istnieje pierwszy element._iter_get(position)zwraca element z bieżącej pozycji, a zmienna pętli otrzymuje tę wartość._iter_next(iter)uruchamia się przed każdym kolejnym przebiegiem. Przechodzi do następnej pozycji i zwracafalse, gdy nie ma już więcej elementów, co kończy pętlę.
# 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 to tablica z jednym miejscem, którą Godot tworzy dla każdej pętli. iter[0] przechowuje pozycję tej pętli, a Godot przekazuje jej wartość do _iter_get(). Team działa teraz w pętli for:
var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
print(member) # Ada, potem BoPrzechowuj pozycję w iter[0], a nie w zmiennej składowej takiej jak _position. Każda pętla ma własne iter, więc dwie pętle przechodzące po tej samej drużynie, nawet gdy jedna znajduje się wewnątrz drugiej, nie zakłócają się nawzajem. W przypadku zmiennej składowej pętla wewnętrzna zmieniałaby pozycję pętli zewnętrznej.
Pozostałe operacje na listach nie mają wirtualnej metody: len(team) i team[0] są błędami. Napisz zwykłe metody o nazwach takich jak w przypadku tablicy, na przykład size(), get_at(index) i has(member). Nie sprawdzaj przynależności za pomocą in: "Ada" in team sprawdza, czy Team ma właściwość lub metodę o nazwie Ada, więc zwraca false.
Wyzwanie
ŁatwyNapisz klasę Bookshelf w pliku bookshelf.gd. Przechowuje tytuły w _titles i może przechowywać najwyżej _capacity książek:
add(title)dodaje tytuł na końcu i zwracatruealbo zwracafalsebez dodawania, gdy półka jest pełna lub zawiera już ten tytuł.size()zwraca liczbę książek, ahas(title)informuje, czy tytuł znajduje się na półce.get_at(index)zwraca tytuł o podanym indeksie lub pusty ciąg, gdy indeks znajduje się poza zakresem półki._iter_init(),_iter_next()i_iter_get()umożliwiają pętliforprzejście przez tytuły w kolejności, w jakiej zostały dodane.
Dostarczony kod odczytuje pojemność, liczbę tytułów i po jednym tytule w każdym wierszu, a następnie wyświetla tytuły, których nie udało się dodać. Wyświetla liczbę książek, wypisuje je za pomocą pętli for przechodzącej po półce, a następnie odczytuje jeszcze jeden tytuł i wyświetla informację, czy znajduje się on na półce, oraz tytuł ostatniej książki. Dla pojemności 3, tytułów Dune, Emma, Dune, Ulysses, Hamlet oraz wyszukiwanego tytułu Emma wyświetli:
Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: UlyssesTwój kod umieść w pliku bookshelf.gd. Plik main.gd zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.
Spróbuj swoich sił
extends Node
func _ready():
# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
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))
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe selfMetodyWłaściwościKonstruktor (_init)Powtórka – prosty kalkulator4Polimorfizm
Ponowne omówienie przesłaniania metodDuck typingKlasy i metody abstrakcyjneProjektowanie interfejsówPowtórzenie – kalkulator kształtów7Sygnały
Czym jest sygnał?Deklarowanie i emitowanieŁączenie z sygnałamiSygnały z argumentamiPodsumowanie — system zdrowia10Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu2Właściwości klas
Zmienne instancji a zmienne statyczneFunkcje statyczneSettery właściwościGettery właściwościPrywatne z konwencjiPodsumowanie — menedżer kont bankowych5Enkapsulacja
Elementy publiczne i prywatneWalidacja za pomocą setterówUkrywanie informacjiWłaściwości tylko do odczytuPodsumowanie – system ewidencji uczniów8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieKlasy wewnętrzneWęzły jako komponentyRefCounted a NodeTypy wyliczeniowe w klasach11Projekt: Zarządzanie biblioteką
Przegląd projektuKlasy książki i użytkownika3Dziedziczenie
Podstawy dziedziczeniaSłowo kluczowe superNadpisywanie metodŁańcuchy dziedziczeniaSprawdzanie typów za pomocą isPodsumowanie – hierarchia pracowników6Metody specjalne
Wprowadzenie do metod wirtualnychMetoda _to_stringWłasne iteratoryPodsumowanie — własna lista9Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec StrategyPoćwicz samodzielnie: Kompilator GDScript online