Traduzido de A hidden gem in Pharo: Generator.
![Julien Delplanque](https://chicoary.wordpress.com/wp-content/uploads/2021/09/7c4a3-1vuzjaoyfu0hqf2luzafvpw.png)
Follow
Mar 27, 2020 · 3 minutos de leitura
De acordo com a wikipedia:
Um generator é uma rotina especial que pode ser usada para controlar o comportamento de iteração de um loop. — Wikipedia
Encontrei generators pela primeira vez em Python. Fico feliz em saber que o Pharo tem suporte integrado para generators. Esta característica fornecida pela classe Generator
parece ser bastante desconhecida pelos Pharoers que conheço, então vamos falar sobre isso.
Seqüência infinita de itens
Romanesco cabbage — Fonte: https://pxhere.com/fr/photo/748888
Com generators, você pode facilmente manipular uma seqüência infinita de itens como um fluxo.
Por exemplo, vamos definir um generator fornecendo uma seqüência infinita de Cores
aleatórias:
colorGenerator := Generator on: [ :generator |
[ generator yield: Color random ] repeat
].
Pode ser também [N.T.]:
colorGenerator := Generator on: [ :generator |
[ generator nextPut: Color random ] repeat
].
seguindo mais a interface pública de uma Stream.
Lembrete: Em Pharo a mensagem
#repeat
enviada a umBlockClosure
faz com que o bloco seja chamado um número infinito de vezes (["do something"]repeat
é equivalente a[true] whileTrue: ["do something"]
).
Agora que o generator está definido, podemos obter um número arbitrário de cores aleatórias utilizando o método `#next’:
colorGenerator next.
colorGenerator next.
colorGenerator next.
...
Quando a mensagem “next” é enviada, o cálculo no bloco que define o “Generator” continua até que seja encontrada uma mensagem yield:
[N.T.: Ou nextPut:
]. A mensagem #yield:
pausa o cálculo e retorna o objeto dado como argumento. Este comportamento é repetido cada vez que é enviada a mensagem #next
.
Seqüência finita de itens
Fonte: https://pxhere.com/fr/photo/748888
Na verdade, você também pode utilizar “Generators” para gerar uma seqüência finita de itens.
Neste caso, o método #atEnd
permite verificar se ainda há itens a serem obtidos do generator. Se #atEnd
retornar false
, isso significa que não há mais itens a serem obtidos do generator. Assim, chamadas subseqüentes para o #next
retornarão nil
.
O exemplo a seguir ilustra este comportamento:
finiteNumberGenerator := Generator on: [ :generator |
1 to: 3 do: [ :i | generator yield: i
].
finiteNumberGenerator atEnd >>> false.
finiteNumberGenerator next >>> 1.
finiteNumberGenerator next >>> 2.
finiteNumberGenerator next >>> 3.
finiteNumberGenerator atEnd >>> true.
finiteNumberGenerator next >>> nil
Conclusão
Neste momento você provavelmente estará pensando: “Ok Julien, mas eu posso fazer o mesmo usando o Iterator design pattern.” e você está totalmente certo. Na verdade, um gerador é um iterador! Mas ele tem 3 principais vantagens:
- Você não precisa criar uma classe para seu iterator, um generator é como um “iterator anônimo”; e
- Você pode escrever um algoritmo gerando uma seqüência infinita de objetos sem ter que se preocupar com o design pattern do iterator, você só precisa utilizar
#yield:
para retornar os valores gerados. - É memory-efficient quando se trata de uma grande coleção de itens, uma vez que só processará um elemento de cada vez e acionará o cálculo deste elemento lazily, quando for necessário.
Para concluir, os geradores do Pharo fornecem uma maneira prática de lidar com uma seqüência infinita de elementos. Você deve começar a usá-los!