Menu
CoddyTech

Itérateurs personnalisés

Fait partie de la section Programmation orientée objet du Journey GDScript de Coddy. Leçon 33 sur 65.

Python permet à une classe de se comporter comme une liste grâce à des méthodes magiques telles que __len__, __getitem__, __contains__ et __iter__. Godot dispose de méthodes virtuelles pour une seule de ces tâches : la boucle for. Trois méthodes permettent à for item in my_object: de fonctionner :

  • _iter_init(iter) s’exécute une fois, avant le premier tour. Elle définit la position de départ et renvoie true s’il existe un premier élément.
  • _iter_get(position) renvoie l’élément à la position actuelle, et la variable de boucle reçoit cette valeur.
  • _iter_next(iter) s’exécute avant chaque tour suivant. Elle passe à la position suivante et renvoie false lorsqu’il n’y a plus d’éléments, ce qui termine la boucle.
# 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 est un tableau avec un emplacement que Godot crée pour chaque boucle. iter[0] contient la position de cette boucle, et Godot transmet sa valeur à _iter_get(). Un Team fonctionne désormais dans une boucle for :

var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
	print(member) # Ada, puis Bo

Conservez la position dans iter[0], et non dans une variable membre telle que _position. Chaque boucle possède son propre iter, donc deux boucles sur la même équipe, même si l’une est imbriquée dans l’autre, ne se perturbent pas. Avec une variable membre, la boucle interne déplacerait la position de la boucle externe.

Les autres opérations sur une liste n’ont pas de méthode virtuelle : len(team) et team[0] sont des erreurs. Écris des méthodes ordinaires portant des noms comme celles d’Array, telles que size(), get_at(index) et has(member). Ne teste pas l’appartenance avec in : "Ada" in team vérifie si Team possède une propriété ou une méthode nommée Ada, donc le résultat est false.

challenge icon

Défi

Facile

Écrivez la classe Bookshelf dans bookshelf.gd. Elle conserve les titres dans _titles et peut contenir au maximum _capacity livres :

  • add(title) ajoute le titre et renvoie true, ou renvoie false sans l’ajouter lorsque l’étagère est pleine ou contient déjà ce titre.
  • size() renvoie le nombre de livres, et has(title) indique si le titre se trouve sur l’étagère.
  • get_at(index) renvoie le titre à cet index, ou une chaîne vide lorsque l’index est en dehors de l’étagère.
  • _iter_init(), _iter_next() et _iter_get() permettent à une boucle for de parcourir les titres dans l’ordre où ils ont été ajoutés.

Le code fourni lit la capacité, le nombre de titres et un titre par ligne, puis signale les titres qu’il n’a pas pu ajouter. Il affiche le nombre de livres, les énumère avec une boucle for sur l’étagère, puis lit un titre supplémentaire et indique si l’étagère le contient, ainsi que le dernier livre. Pour une capacité de 3, les titres Dune, Emma, Dune, Ulysses, Hamlet et la recherche Emma, le programme affiche :

Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: Ulysses

Votre code doit être placé dans bookshelf.gd. main.gd contient le code d’entrée/sortie fourni et ne peut pas être modifié.

Essayez vous-même

extends Node

func _ready():
	# Code d'entrée/sortie fourni : laissez-le tel quel
	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))
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Compilateur GDScript en ligne