Ruby/Struktury sterujące

Z Wikibooks, biblioteki wolnych podręczników.

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.