Iteradores personalizados
Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 33 de 65.
Python permite que una clase se comporte como una lista con métodos mágicos como __len__, __getitem__, __contains__ y __iter__. Godot tiene métodos virtuales para solo una de estas tareas: el bucle for. Tres métodos hacen que for item in my_object: funcione:
_iter_init(iter)se ejecuta una vez, antes de la primera iteración. Establece la posición inicial y devuelvetruesi hay un primer elemento._iter_get(position)devuelve el elemento en la posición actual, y la variable del bucle recibe ese valor._iter_next(iter)se ejecuta antes de cada iteración posterior. Avanza a la siguiente posición y devuelvefalsecuando no quedan más elementos, lo que finaliza el bucle.
# 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 es un Array con un espacio que Godot crea para cada bucle. iter[0] contiene la posición de ese bucle, y Godot pasa su valor a _iter_get(). Ahora, un Team funciona en un bucle for:
var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
print(member) # Ada, luego BoMantén la posición en iter[0], no en una variable miembro como _position. Cada bucle tiene su propio iter, así que dos bucles sobre el mismo equipo, incluso uno dentro del otro, no interfieren entre sí. Con una variable miembro, el bucle interno movería la posición del bucle externo.
Las demás operaciones de lista no tienen un método virtual: len(team) y team[0] son errores. Escribe métodos ordinarios con nombres como los de Array, por ejemplo, size(), get_at(index) y has(member). No compruebes la pertenencia con in: "Ada" in team comprueba si Team tiene una propiedad o un método llamado Ada, así que es false.
Desafío
FácilEscribe la clase Bookshelf en bookshelf.gd. Guarda los títulos en _titles y admite como máximo _capacity libros:
add(title)añade el título y devuelvetrue, o devuelvefalsesin añadirlo cuando la estantería está llena o ya tiene ese título.size()devuelve el número de libros yhas(title)indica si el título está en la estantería.get_at(index)devuelve el título en ese índice, o una cadena vacía cuando el índice está fuera de los límites de la estantería._iter_init(),_iter_next()y_iter_get()permiten que un bucleforrecorra los títulos en el orden en que se añadieron.
El código proporcionado lee la capacidad, el número de títulos y un título por línea, e informa de los títulos que no pudo añadir. Imprime el número de libros, los enumera con un bucle for sobre la estantería, luego lee un título más e imprime si la estantería lo tiene y cuál es el último libro. Para una capacidad de 3, los títulos Dune, Emma, Dune, Ulysses, Hamlet y la búsqueda Emma, imprime:
Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: UlyssesEscribe tu código en bookshelf.gd. main.gd contiene el código de entrada y salida proporcionado y no se puede editar.
Pruébalo tú mismo
extends Node
func _ready():
# Código de entrada/salida proporcionado: mantenlo tal como está
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))
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de la programación orientada a objetos
Archivos externosIntroducción a la programación orientada a objetosClases vs. objetosLa palabra clave selfMétodosPropiedadesConstructor (_init)Repaso: calculadora sencilla4Polimorfismo
Repaso de la sobrescritura de métodosTipado patoClases y métodos abstractosDiseño de interfacesRepaso: calculadora de formas7Señales
¿Qué es una señal?Declarar y emitirConectarse a las señalesSeñales con argumentosRepaso: sistema de salud10Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite2Propiedades de clase
Variables de instancia y estáticasFunciones estáticasMétodos setter de propiedadesMétodos getter de propiedadesPrivado por convenciónRepaso: administrador de cuentas bancarias5Encapsulación
Miembros públicos y privadosValidación con settersOcultación de informaciónPropiedades de solo lecturaRepaso: sistema de registros de estudiantes8Conceptos avanzados de POO
Composición frente a herenciaClases internasNodos como componentesRefCounted frente a NodeEnums en clases3Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosCadenas de herenciaComprobaciones de tipo con isRepaso: jerarquía de empleados6Métodos especiales
Introducción a los métodos virtualesEl método _to_stringIteradores personalizadosRepaso: lista personalizada9Patrones de diseño, parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón StrategyPractica por tu cuenta: Compilador de GDScript online