Wyrażenia warunkowe
W poniższym rozdziale nauczysz się używać jednych z dwu (obok pętli) najważniejszych konstrukcji w programowaniu - wyrażeń warunkowych. Najpierw jednak poznamy pewne metody, dzięki którym nasze programy staną się interaktywne - dzięki temu łatwiej będzie nam się uczyć kolejnych zagadnień.
Interaktywność
Praktycznie każdy zaawansowany program oferuje użytkownikowi jakiś stopień interaktywności. Inaczej mówiąc, program komunikuje się z użytkownikiem i vice versa. Wiemy już jak w Rubym program może “powiedzieć” coś użytkownikowi - np. za pomocą metod puts i print. Pora dowiedzieć się jak użytkownik programu może coś mu “powiedzieć”. Służy do tego metoda gets:
#File: Floor.rb puts "Type a number:" n = gets puts "Floor:" puts n.to_i
jan@Stacja-Linux ~/Pulpit $ ruby Integer.rb Type a number:
Przeanalizujmy powyższy program. Najpierw wyświetlany jest napis “Type a number:”. W następnej linijce, na zmienną n przypisywany jest wynik metody gets. Ale co jest jej wynikiem? To co wpisze użytkownik ;) Wpiszmy więc coś (np. 15.6) i wciśnijmy enter:
jan@Stacja-Linux ~/Pulpit $ ruby Integer.rb Type a number: 15.6 Floor: 15
Otrzymaliśmy podłogę podanej liczby, ale jak to się stało? Po przypisaniu napisu "15.6" na zmienną n, wyświetlony został napis "Floor:". Następnie wyświetlona została zmienna n, przekształcona na typ liczby całkowitej (Przekształcenie to (zwane rzutowaniem lub konwersją) jest tu niezbędne, gdyż wynikiem metody gets jest zawsze napis). Zauważ, że powyższy program można napisać krócej i bez użycia zmiennych (ale chyba kosztem czytelności ;)):
#File: Floor2.rb puts “Type a number:” puts “Floor\n #{gets.to_i}”
Wyrażenie warunkowe if
Do tej pory pisaliśmy programy, które robiły to samo, niezależnie od otrzymanych danych (jedynymi możliwymi urozmaiceniami były błędy, gdy przekazane dane były niewłaściwe ;)). Pora to zmienić!
Przeanalizujmy wyrażenie if. Składnia jest następująca:
if (WARUNEK)
INSTRUKCJE
elsif (INNY_WARUNEK)
INNE_INSTRUKCJE
else
JESZCZE_INNE_INSTRUKCJE
end
To co dzieje się po wykonaniu kodu zgodnego z powyższym schematem jest bardzo intuicyjne. Jeśli spełniony (tj. o wartości logicznej true) jest WARUNEK przy słowie kluczowym if, wykonają się INSTRUKCJE poniżej, aż do kolejnego słowa kluczowego (w tym przypadku elsif). Jeśli zaś WARUNEK ma wartość false, INSTRUKCJE te nie będą wykonane i nastąpi ewaluacja WARUNKU przy słowie elsif. Jeśli INNY_WARUNEK jest spełniony wykonają się INNE_INSTRUKCJE poniżej, aż do kolejnego słowa kluczowego (w tym przypadku else), w przeciwnym wypadku wykona się kod między słowami else i end.
Ilość warunków elsif jest dowolna, więc poprawne będą również wyrażenia o schemacie jak poniżej...:
if (WARUNEK_1)
INSTRUKCJE_1
elsif (WARUNEK_2)
INSTRUKCJE_2
elsif (WARUNEK_3)
INSTRUKCJE_3
elsif (WARUNEK_4)
INSTRUKCJE_4
else
INSTRUKCJE_5
end
... i poniżej:
if (WARUNEK_1)
INSTRUKCJE_1
else
INSTRUKCJE_5
end
Co więcej, słowo kluczowe else, które “zbiera pozostałe przypadki” również nie jest obowiązkowe. Warunki nie muszą zaś być objęte w nawiasy (ale czasem poprawia to czytelność kodu). Poprawny będzie więc zapis:
if WARUNEK
INSTRUKCJE
end
Spróbujmy teraz napisać i przeanalizować program, który sprawdzi, czy podana liczba jest podzielna przez 13:
#File: Divisibility.rb puts "Type a number:" n = gets.to_f if n%13==0 puts "#{n} is divisible by 13" end
Powyższy program prosi użytkownika o liczbę. Jeśli podana liczba jest podzielna przez 13, program wypisuje stosowny komunikat. W przeciwnym przypadku… nie robi nic. Spróbujmy przerobić ten program tak, aby był bardziej user-friendly:
#File: Divisibility2.rb puts "Type a number:" n = gets.to_f if n%13==0 puts "#{n} is divisible by 13" else puts "#{n} is NOT divisible by 13" end
Teraz jeśli liczba nie będzie podzielna przez 13, użytkownik również otrzyma stosowną wiadomość.
Poniżej przykład programu (liczącego ilość miejsc zerowych w funkcji kwadratowej) z większą ilością warunków. Zauważ, że wyrażania warunkowe mogą być zagnieżdżone (tj. w instrukcjach pod jednym z warunków może znaleźć się kolejny if, a w nim kolejny, a w nim kolejny...):
#File: Roots.rb puts "Define a in f(x) = ax**2+bx+c:" a = gets.to_f puts "Define b in f(x) = ax**2+bx+c:" b = gets.to_f puts "Define c in f(x) = ax**2+bx+c:" c = gets.to_f if a == 0 if b == 0 if c == 0 puts "f(x) = 0 has an infinite number of roots ;)" else puts "f(x) = #{c} has no roots" end else puts "f(x) = #{b}x+#{c} has one root" end else d = b**2 - 4*a*c if d > 0 puts "f(x) = #{a}x**2+#{b}x+#{c} has two roots" elsif d == 0 puts "f(x) = #{a}x**2+#{b}x+#{c} has one root" else puts "f(x) = #{a}x**2+#{b}x+#{c} has no roots" end end
Na koniec tego rozdziału mała ciekawostka. Skrócony zapis trójargumentowego wyrażenia warunkowego:
WARUNEK ? INSTRUKCJE_1 : INSTRUKCJE_2
Powyższy schemat kodu jest równoważny poniższemu:
if (WARUNEK)
INSTRUKCJE_1
else
INSTRUKCJE_1
end
Poniżej wykorzystanie operatora trójargumentowego na przykładzie naszego programu badającego podzielność przez 13 (operator trójargumentowy jest stosowany, gdy kod instrukcji do wykonania jest krótki - w przeciwnym wypadku, bardziej czytelny jest standardowy if):
#File: Divisibility3.rb puts "Type a number:" n = gets.to_f puts "#{n} is#{ n%13==0 ? "" : " NOT" } divisible by 13"
Dla ciekawych świata:
Więcej informacji na temat wyrażeń warunkowych (między innymi wyrażenia unless oraz case, dla których zabrakło miejsca w samouczku ;))