Ruby/Iteratory: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Szymon wro (dyskusja | edycje)
Szymon wro (dyskusja | edycje)
mNie podano opisu zmian
Linia 1:
== Iteratory ==
 
Iteratory nie są oryginalnym pojęciem Rubiego. Są one w powszechnym użyciu w językach programowania zorientowanych obiektowo. Występują również w Lispie, choć nie są tam nazywane iteratorami. Jednakże koncepcja iteratorów jest wielu osobom obca, więc tutaj zostanie oneona tutaj wyjaśniona nieco bardziej szczegółowo.
 
Czasownik "iterować" oznacza wykonywać tę samą czynność wiele razy, tak więc iterator jest czymś co wykonuje tę samą rzeczyrzecz wiele razy.
 
Podczas pisania kodu potrzebujemy pętli w wielu różnych sytuacjach. W C, kodujemy je używając ''<tt>for''</tt> lub ''<tt>while''</tt>. Na przykład,
 
<pre>
Linia 14:
</pre>
 
Składnia pętla ''<tt>for (...)''</tt> z języka C dostarcza pewnej abstrakcji, która pomaga w utworzeniu pętli, ale sprawdzenie czy ''<tt>*str''</tt> nie wskazuje na znak pusty znak wymaga od programisty znajomości szczegółów o wewnętrznej strukturze łańcucha znakowego. Sprawia to, że C jest odczuwany jako język niskiego poziomu. Języki wyższego poziomu odznaczają się bardziej elastycznym wsparciem iteracji. Rozważ następujący skrypt ''sh'' powłoki systemowej:
 
<pre>
Linia 26:
Wszystkie pliki źródłowe i nagłówkowe języka C w bieżącym katalogu są przetwarzane i powłoka systemowa bierze na siebie detale dotyczące wskazywania i podstawiania po kolei wszystkich nazw plików, jedna po drugiej. To chyba działa na wyższym poziomie niż C, nie sądzisz?
 
Trzeba zauważyć jeszcze jedno: często język dostarcza iteratorów dla typów wbudowanych, ale rozczarowuje gdy okazuje się, że musimy wracać z powrotem do pętli nisko poziomowych by iterować nasze własne typy danych. W programowaniu zorientowanym obiektowo (OOP - ang. ''Object-Oriented Programming''), użytkownicy zazwyczaj definiują własne typy danych jeden za drugim, więc to może być całkiem poważnym problemem.
 
Tak więc każdy język wspierający OOP zawiera jakieś udogodnienia do iterowania. Niektóre języki dostarczają w tym celu specjalnych klas; Ruby pozwala na definiowanie iteratorów bezpośrednio.
 
Typ ''<tt>String''</tt> Rubiego posiada kilka użytecznych iteratorów:
 
<pre>
Linia 38:
</pre>
 
''<tt>each_byte''</tt> to iterator wskazujący na każdy znak w łańcuchu. Każdy znak jest podstawiany do zmiennej lokalnej ''<tt>c''</tt>. To samo można przełożyć na coś bardziej przypominającego kod C...
 
<pre>
Linia 50:
</pre>
 
... jednakże, iterator ''<tt>each_byte''</tt> jest koncepcyjnie prostszy, jak i wydaje się, że działałby nadal nawet gdyby klasa ''<tt>String''</tt> uległa w przyszłości radykalnym modyfikacjom. Dużą zaletą iteratorów jest to, że zachowują one swoje poprawne działanie na przekór takim radykalnym zmianom;. iI w rzeczy samej, jest to charakterystyczna cecha dobrego kodu w ogólności. (Tak, miej cierpliwość, niebawem będziemy mówić również o tym czym są klasy.)
 
Innym iteratorem klasy ''<tt>String''</tt> jest ''<tt>each_line''</tt>.
 
<pre>
Linia 64:
Zadania które pochłonęły by większość wysiłku w C (wyszukiwanie ograniczników linii, generowanie podłańcuchów, itd.) z użyciem iteratorów mogą być łatwo rozwiązane.
 
Instrukcja ''<tt>for''</tt> pojawiająca się w [[Ruby/Struktury sterujące|poprzednim rozdziale]] dokonywała iteracji przez użycie iteratora ''<tt>each''</tt>. Iterator ''<tt>each''</tt> klasy <tt>String</tt> działa w ten sam sposób jak ''<tt>each_line''</tt>, więc przepiszmy powyższy przykład z ''<tt>for''</tt>:
 
<pre>
Linia 76:
</pre>
 
Możemy używać struktury sterującej ''<tt>retry''</tt> w połączeniu z iterowaną pętlą. PowodujeSpowoduje ona rozpoczęcie iterowania pętli od początku.
 
<pre>
Linia 94:
</pre>
 
Zamienienie ''<tt>retry''</tt> na ''<tt>redo''</tt> w powyższym przykładzie spowoduje, że tylko bieżąca iteracja będzie wykonana ponownie, z następującym wynikiem:
 
012
234
 
''<tt>yield''</tt> jest wyrażeniem, które pojawia się czasem w definicji iteratora. ''<tt>yield''</tt> przenosi sterowanie do bloku kodu który został przekazany do iteratora (wyjaśnimy to dogłębniej w [[Ruby/Procedury jako obiekty|rozdziale]] poświęconym obiektom - procedurom). Następujący przykład definiuje iterator ''<tt>repeat''</tt>, który powtarza blok kodu określoną ilość razy przekazaną jako argument.
 
<pre>
Linia 116:
</pre>
 
Używając ''<tt>retry''</tt> można zdefiniować iterator który będzie działał mniej więcej jak standardowa pętla ''<tt>while''</tt>.
 
<pre>