Modifica Penso di capire la tua domanda ora, terrò ancora la mia risposta originale qui sotto.
y << a
è uno pseudonimo per y.yield(a)
, che è fondamentalmente un sleep
con valore di ritorno. Ogni volta che viene richiesto un valore dall'enumeratore con next
, l'esecuzione viene continuata fino a quando non viene restituito un altro valore.
Enumerators non hanno bisogno di elencare un numero finito di elementi, in modo che sono infinito. Ad esempio, fib.to_a
non si interromperà mai, perché tenta di creare un array con un numero infinito di elementi.
Come tali, gli enumeratori sono grandi come una rappresentazione di serie infinite come i numeri naturali o, nel tuo caso, i numeri di Fibonacci. L'utente dell'enumeratore può decidere quanti valori ha bisogno, quindi nell'esempio take(10)
determina la condizione di interruzione se lo si desidera.
Lo stato di interruzione si trova nell'implementazione di Enumerator#take
. A scopo dimostrativo, siamo in grado di rendere la nostra applicazione chiamata my_take
:
class Enumerator
def my_take(n)
result = []
n.times do
result << self.next
end
result
end
end
dove si poteva, naturalmente, "mentalmente sostituire" il ciclo n.times
con il C stile classico for (i=0; i<n; i++)
. C'è la tua condizione di rottura. self.next
è il metodo per ottenere il valore successivo del enumeratore, che è possibile utilizzare anche al di fuori della classe:
fib.next
#=> 1
fib.next
#=> 1
fib.next
#=> 2
fib.next
#=> 3
Detto questo, si può ovviamente costruire un enumeratore che enumera un numero finito di valori, come ad esempio i numeri naturali in un determinato intervallo, ma non è questo il caso. Quindi, l'Enumeratore genererà un errore StopIteration
quando si tenta di chiamare next
, ma tutti i valori sono già stati enumerati. In tal caso, hai due condizioni di pausa, per così dire; quello che si rompe prima vincerà. take
in realtà lo gestisce salvando dall'errore, quindi il codice seguente è un po 'più vicino all'implementazione reale (tuttavia, take
è in realtà implementato in C).
class Enumerator
def my_take(n)
result = []
n.times do
result << self.next
end
result
rescue StopIteration
# enumerator stopped early
result
end
end
Molto interessante! –