Menu
CoddyTech

Pattern Iterator

Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 64 di 70.

Quando hai una raccolta di elementi memorizzati all'interno di un oggetto, spesso vuoi scorrerli con un ciclo. Il ciclo generico for di Lua funziona con qualsiasi funzione iteratrice: chiama la funzione prima di ogni iterazione e si ferma quando la funzione restituisce nil.

Il pattern Iterator fornisce all’oggetto un metodo che restituisce una funzione del genere. La funzione mantiene la propria posizione in una variabile locale, quindi la posizione appartiene a un ciclo, non alla raccolta:

local Collection = {}
Collection.__index = Collection

function Collection:new()
    local obj = { items = {} }
    setmetatable(obj, Collection)
    return obj
end

function Collection:add(item)
    table.insert(self.items, item)
end

function Collection:iter()
    local index = 0
    return function()
        index = index + 1
        return self.items[index]
    end
end

Ogni chiamata a bag:iter() crea una nuova funzione con il proprio index, che parte da 0. La funzione è una closure: può continuare a usare index e self anche dopo che iter ha restituito un valore. Dopo l’ultimo elemento, self.items[index] è nil e il ciclo si interrompe:

local bag = Collection:new()
bag:add("apple")
bag:add("banana")

for item in bag:iter() do
    print(item)  -- apple, poi banana
end

for item in bag:iter() do
    print(item)  -- apple, poi di nuovo banana
end

Mantieni la posizione fuori dalla raccolta stessa. Se l'oggetto memorizzasse self.index e fungesse da iteratore di se stesso, il primo ciclo lascerebbe l'indice alla fine, quindi un secondo ciclo non stamperebbe nulla, mentre un ciclo interrotto in anticipo con break farebbe iniziare il ciclo successivo a metà.

challenge icon

Sfida

Facile

Creiamo una classe Playlist che puoi scorrere con il ciclo generico for di Lua! Implementerai il pattern Iterator con un metodo :iter() che restituisce una funzione iteratore.

Organizzerai il codice in due file:

  • Playlist.lua: crea una classe Playlist che memorizza internamente i brani. La tua classe deve avere un costruttore :new() che inizializza un elenco di brani vuoto e un metodo :addSong(title) che vi aggiunge un brano. Soprattutto, aggiungi un metodo :iter() che restituisce una nuova funzione ogni volta che viene chiamato. Questa funzione memorizza la propria posizione in una variabile locale e restituisce il brano successivo a ogni chiamata, oppure nil quando non ci sono altri brani.
  • main.lua: richiedi il modulo Playlist e crea una nuova playlist. Aggiungi i brani in base agli input ricevuti, poi usa un ciclo generico for su playlist:iter() per stampare il titolo di ogni brano su una riga separata.

Poiché ogni chiamata a :iter() inizia dal primo brano, puoi scorrere la stessa playlist un numero qualsiasi di volte.

Riceverai tre input, ciascuno dei quali rappresenta il titolo di un brano da aggiungere alla playlist (nell'ordine).

Ad esempio, se gli input sono Bohemian Rhapsody, Stairway to Heaven e Hotel California, l'output dovrebbe essere:

Bohemian Rhapsody
Stairway to Heaven
Hotel California

Se gli input sono Yesterday, Imagine e Let It Be, l'output dovrebbe essere:

Yesterday
Imagine
Let It Be

Provalo tu

-- Carica il modulo Playlist con require
local Playlist = require('Playlist')

-- Leggi tre titoli di canzoni dall'input
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()

-- TODO: Crea una nuova playlist usando Playlist:new()

-- TODO: Aggiungi le tre canzoni alla playlist usando :addSong()

-- TODO: Usa un ciclo for generico su playlist:iter()
-- e stampa il titolo di ogni canzone su una riga separata
-- Suggerimento: for song in playlist:iter() do ... end
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Lua online