Ruby/Struktury sterujące
Struktury sterujące
[edytuj]Ten rozdział odkrywa nieco więcej na temat struktur sterujących Rubiego.
case
[edytuj]Instrukcji case używamy do sprawdzenia sekwencji warunków. Na pierwszy rzut oka jest ona podobna do instrukcji switch z języka C lub Java ale, jak za chwilę zobaczymy, znacznie potężniejsza.
def okresl(i)
case i
when 1, 2..5
puts "1..5"
when 6..10
puts "6..10"
end
end
okresl(8) #=> 6..10
2..5 jest wyrażeniem oznaczającym przedział zamknięty od 2 do 5. Następujące wyrażenie sprawdza czy wartość i należy do tego przedziału:
(2..5) === i
case wewnętrznie używa operatora relacji === by sprawdzić kilkanaście warunków za jednym razem. W odniesieniu do obiektowej natury Rubiego, === jest interpretowany odpowiednio dla obiektu który pojawia się jako warunek w instrukcji when. Na przykład, następujący kod sprawdza równość łańcuchów znakowych w pierwszym wyrażeniu when oraz zgodność wyrażeń regularnych w drugim when.
def okresl(s)
case s
when 'aaa', 'bbb'
puts "aaa lub bbb"
when /def/
puts "zawiera def"
end
end
okresl("abcdef") #=> zawiera /def/
while
[edytuj]Ruby dostarcza wygodnych sposobów do tworzenia pętli, chociaż jak odkryjesz w następnym rozdziale, wiedza o tym jak używać iteratorów często zaoszczędzi ci bezpośredniego pisania własnych pętli.
while jest powtarzanym if. Używaliśmy tej instrukcji w naszej słownej zgadywance i w programach sprawdzających wyrażenia regularne (zobacz poprzedni rozdział). Tutaj instrukcja ta przyjmuje formę while warunek ... end otaczającą blok kodu który będzie powtarzany dopóty, dopóki warunek jest prawdziwy. Ale while i if mogą być łatwo zaaplikowane również do pojedynczych wyrażeń:
irb(main):001:0> i = 0 => 0 irb(main):002:0> puts "To jest zero." if i == 0 To jest zero. => nil irb(main):003:0> puts "To jest liczba ujemna" if i < 0 => nil irb(main):004:0> puts i += 1 while i < 3 1 2 3 => nil
Czasami będziesz chciał zanegować sprawdzany warunek. unless jest zanegowanym if, natomiast until zanegowanym while. Jeśli chcesz, poeksperymentuj z tymi instrukcjami.
Są cztery sposoby do przerywania wykonywania pętli z jej wnętrza. Pierwszy, to zastosowanie instrukcji break. Powoduje, tak jak w C, zupełną ucieczkę z pętli. Drugi, to zastosowanie instrukcji next. Powoduje ona przeskoczenie na początek kolejnej iteracji (podobnie jak znane z C continue). Trzeci, to użycie specyficznej dla Rubiego instrukcji redo, która powoduje ponowne wykonanie bieżącej iteracji. Następujący kod w języku C ilustruje znaczenie instrukcji break, next i redo:
while (warunek) {
etykieta_redo:
goto etykieta_next; /* w Rubim: "next" */
goto etykieta_break; /* w Rubim: "break" */
goto etykieta_redo; /* w Rubim: "redo" */
...
...
etykieta_next:
}
etykieta_break:
...
Czwarty sposób by wyjść z pętli będąc w jej wnętrzu to użycie instrukcji return. Jej wywołanie spowoduje wyjście nie tylko z pętli ale również z metody, która tę pętlę zawiera. Jeżeli podany został argument, będzie on zwrócony jako rezultat wywołania metody. W przeciwnym wypadku zwracane jest nil.
for
[edytuj]Programiści C mogą się zastanawiać jak zrobić pętlę "for". Petla for Rubiego może służyć w ten sam sposób, choć jest nieco bardziej elastyczna. Pętla poniżej iteruje każdy element w kolekcji (tablicy, tablicy asocjacyjnej, sekwencji numerycznej, itd.), ale nie zmusza programisty do myślenia o indeksach:
for element in kolekcja
# ... "element" wskazuje na element w kolekcji
end
Kolekcją może być przedział wartości (to właśnie większość ludzi ma na myśli, gdy mówi o pętli for):
for num in (4..6)
print num
end
#=> 456
W tym przykładzie przeiterujemy kilka elementów tablicy:
for elem in [100, -9.6, "zalewa"]
puts "#{elem}\t(#{elem.class})"
end
#=> 100 (Fixnum)
# -9.6 (Float)
# zalewa (String)
Ale tak naprawdę for jest po prostu innym sposobem zapisania instrukcji each, która jest naszym pierwszym przykładem iteratora. Poniższe formy są równoważne:
Jeżeli przywykłeś do C lub Javy, możesz preferować tą.
for element in kolekcja
...
end
Natomiast programista Smalltalka może preferować taką.
kolekcja.each {|element|
...
}
Iteratory często mogą być używane zamiast konwencjonalnych pętli. Jak już nabierzesz wprawy w ich użyciu, stają się zazwyczaj łatwiejsze w użyciu od pętli. Ale zanim dowiemy się więcej o iteratorach, poznajmy jedną najciekawszych konstrukcji języka Ruby: domknięcia.