Wykład nr 2
Instrukcje sterujące języka
Warunki
Instrukcja warunkowa IF
if (file_name =˜ /n.rb$/) (then)
lang = "ruby"
elsif (file_name =˜ /n.pl$/) (then)
lang = "perl"
else
lang = "unknown"
end
//if zwraca wartość ostatniego obliczonego wyrażenia
lang =
if (file_name =˜ /n.rb$/) (then)
"ruby"
elsif (file_name =˜ /n.pl$/) (then)
"perl"
else
"unknown"
end
then lub : wymagane w przypadku jednolinijkowców
lang =
if (file_name =˜ /n.rb$/) then "ruby"
elsif (file_name =˜ /n.pl$/) then "perl"
else "unknown"
end
lang =
if (file_name =˜ /n.rb$/) :"ruby"
elsif (file_name =˜ /n.pl$/) :"perl"
else "unknown"
end
Instrukcja warunkowa UNLESS
unless (file_name =˜ /n.rb$/)
hint = "czemu nie Ruby?"
else
hint = "dobry wybór!"
end
hint = (file_name =˜ /n.rb$/ ? "dobry wybór!" : "czemu nie Ruby?")
if oraz unless jako modyfikatory:
puts "person = #{person}" if debug
puts person.name unless person.nil?
Instrukcja warunkowa - idiom Rubiego
Mamy zmienną „words”, która chcemy wykorzystać jako tablicę słów. Chcemy dodać element, lecz nie wiemy, czy tablica została zainicjowana. Możemy to zrobić nastepująco:
if words.nil?
words = []
end
words << "new word"
Najlepiej jednak wykorzystać ten idiom Rubiego:
words ||= []
words << "new word"
Algebra Boole'a
Jakie obiekty maja wartość true w Rubim? Wszystko co:
- nie jest wartością pustą (nil)
- nie jest fałszem (false)
0, pusty łańcuch, pusta tablica nie mają wartosci „fałsz”
and &&
or ||
not !
if person && person.address
puts "#{person} #{person.address}"
end
Równość
- == „naturalna” równość
- eql? ten sam typ i identyczna wartość
- equal? to samo object_id
- < <= >= >
- <=> (-1,0,1)
- = dopasowanie wyrażen regularnych
- === komparator w instrukcji case
(uwaga: symbole i liczby typu Fixnum posiadają zawsze tylko jedną instancję dla danej wartości)
0 == 0.0 #=> true
"ala" == "ala" #=> true
[1,2,3] == [1,2,3] #=> true
1 == 1.0 #=> true
1.eql? 1.0 #=> false
"ala".eql? "ala" #=> true
1.0.eql? 1.0 #=> true
1.0.equal? 1.0 #=> false
"ala".equal? "ala" #=> false
:ala.equal? :ala #=> true
(1..2) === 1.5 #=> true
Fixnum === 1 #=> true
/ˆa/ === "ala" #=> true
Równość - eql?
values = {}
values[1] = "jeden"
values[1.0] = "jeden"
values
#=> {1=>"jeden", 1.0=>"jeden"}
names = {}
names["Ala"] = "Kowalska"
names["Ala"] = "Smith"
names
#=> {"Ala"=>"Smith"}
Instrukcja selekcji
case month
when 1
month_name = "styczen"
when 2
month_name = "luty"
when 3
month_name = "marzec"
#...
end
predykat === wykorzystywany jest do porównywania:
century =
case year
when 1901..2000
"XX"
when 2001..2100
"XXI"
else
"ciemne wieki"
end
language =
case file_name
when /n.rb$/
"Ruby"
when /n.pl$/
"Perl"
when /n.java$/
"Java"
else
"Unknown"
end
people =
case person
when String
[Person.new(:name => person)]
when Array
person when Person [person]
end
Bloki
Bloki - problem
def even(tab)
result = []
for e in tab
if e % 2 == 0 # tylko ta linia jest inna
result << e
end
end
result
end
def odd(tab)
result = []
for e in tab
if e % 2 != 0 # tylko ta linia jest inna
result << e
end
end
result
end
Bloki - definicja
def three_times
yield
yield
yield
end
three_times{puts "Hello!"}
# "Hello!"
# "Hello!"
# "Hello!"
three_times do
puts "Hello!"
end
Bloki - przekazywanie wartości
def three_times
yield 1
yield 2
yield 3
end
three_times{|i| puts "Hello! #{i}"}
# "Hello! 1"
# "Hello! 2"
# "Hello! 3"
def three_times
puts yield(1)
puts yield(2)
puts yield(3)
end
three_times{|i| i * 5}
# 5
# 10
# 15
Bloki - rozwiązanie problemu
def select(tab)
result = []
for e in tab
if yield(e)
result << e
end
end
result
end
select(tab){|e| e % 2 == 0}
select(tab){|e| e % 2 != 0}
# select jest juz zaimplementowany dla klasy Array tab.select{|e| e % 2 == 0}
Bloki - block_given
def open(file_name)
file = File.open(file_name)
if block_given?
yield(file)
file.close
else
file
end
end
file = open("plik.txt")
# operacje na pliku
file.close
open("plik.txt") do |file|
# operacje na pliku
end
Pętle
Typy pętli
- loop
- while, until
- for
- times, upto, downto, step
- each
Loop
loop do
puts "petla nieskonczona :-)"
end
Kontrola pętli
- break – opuszcza aktualną pętlę
- redo – powtarza iterację bez sprawdzania warunku lub pobierania następnego elementu
- next – następna iteracja
- retry – powtarza całą pętlę (używac z rozwagą)
loop do
line = gets
break if line.nil?
puts line.upcase
end
Pętle while i until
while – wykonywana dopóki warunek jest prawdziwy
index = 1
while line = gets
print "#{index}. #{line}"
index += 1
end
until – wykonywana do czasu gdy warunek stanie sie prawdziwy
value = 12345678
sum = 0
until value <= 0
sum += (value / 10) % 10
value /= 10
end
puts sum
Pętla for
Petla for może być pętla numeryczna:
for index in 10...30
print "#{index}. "
end
Może również służyć do iterowania po strukturach sekwencyjnych:
for word in %w{Ala ma kota Mamrota}
puts word
end
for number, letter in {1 => "A", 2 => "B", 3 => "C"}
puts "#{number}. #{letter}"
end
Pętle "numeryczne"
times – określona ilość razy
3.times{ print "Ho! "} => "Ho! Ho! Ho! "
upto – od wartości minimalnej do maksymalnej
10.upto(20){|x| print x," "} => "10 11 12 13 14 15 16 17 18 19 20"
downto – od wartości maksymalnej do minimalnej
20.downto(10){|x| print x," "} => "20 19 18 17 16 15 14 13 12 11 10"
step – z określonym krokiem
0.step(100,10){|x| print x," "} => "0 10 20 30 40 50 60 70 80 90 100 "
Pętla each
each – najczęściej wykorzystywana w roli pętli
(1...30).each do |index|
print "#{index}. "
end
%w{Ala ma kota Mamrota}.each do |word|
puts word
end
{1 => "A", 2 => "B", 3 => "C"}.each do |number,letter|
puts "#{number}. #{letter}"
end
File.open("myfile.txt").each.with_index do |line,index|
puts "#{index + 1}. #{line}"
end
Wyjątki
- używane są jako mechanizm obsługi błędów
- oferują alternatywną drogę przekazywania informacji do kodu nadrzędnego z wywoływanej funkcji
- pozwalają na obsługę błędu na dowolnym poziomie wywołania
Podejście tradycyjne
def open_file(file_name)
# otwórz plik
if File.exist?(file_name)
# jesli wszystko jest ok, przekaz deskryptor pliku
File.open(file_name)
else
# jesli nie, zwróć kod błedu
-1
end
end
def read_file(file_name,size)
file = open_file(file_name)
if file == -1
puts "Nie mozna otworzyc pliku #{file_name}" return -1
end
result = file.read(size)
file.close
result
end
result = read_file("plik1.txt",10)
if result == -1
return
else
puts result
end
result = read_file("plik2.txt",20)
if result == -1
return
else
puts result
end
result = read_file("plik3.txt",30)
if result == -1
return
else
puts result
end
Użycie wyjątków
def open_file(file_name)
File.open(file_name)
# moze rzucic wyjatek, jesli np. nie ma pliku
# prawa do pliku są niewłaściwe, etc.
end
def read_file(file_name,size)
file = open_file(file_name)
# przekazuje na wyższy poziom wyjątek,
# który może pojawić sie w open_file
result = file.read(size)
# tutaj również może pojawić sie wyjątek
file.close
# oraz tutaj
result
end
begin
puts read_file("plik1.txt",10)
puts read_file("plik2.txt",20)
puts read_file("plik3.txt",30)
rescue Exception => exception
puts exception
return
end
Obsługa wyjątków
begin
# kod, który może rzucić wyjątek
rescue ExceptionType => exception
# kod obsługi wyjatku
ensure
# kod, który zostanie wykonany niezależnie
# od wystąpienia, bądź niewystąpienia wyjątku
end
begin
# kod, który może rzucić wyjątek
rescue ExceptionType1 => exception
# kod obsługi wyjątku typu ExceptionType1
rescue ExceptionType2 => exception
# kod obsługi wyjątku typu ExceptionType2
rescue
# kod obsługi wyjatku StandardError
rescue Exception => exception
# kod obsługujący wszystkie pozostałe wyjatki
end
def file_operation(file_name)
begin file = File.open(file_name)
# operacje na pliku
rescue Errno::ENOENT => exception
puts "Plik #{file_name} nie istnieje"
rescue Errno::EACCES => exception
puts "Nie mozna odczytac pliku #{file_name}"
rescue Exception => exception
puts "Wystapił nieoczekiwany problem " + exception
end
end
Rzucanie wyjątków
raise "Invalid argument"
# Błąd typu RuntimeError
raise Exception.new("Invalid file name")
# Błąd typu Exception
raise
# Błąd typu RuntimeError pozbawiony komunikatu
begin
File.open(file_name)
rescue Exception => exception
logger.error(exception)
# ponowne rzucenie przechwyconego wyjątku
raise
end
Rzucanie wyjątków własengo typu
class MyException < Exception
end
raise MyException.new("Niepoprawna operacja") begin
# kod, który moze rzucić wyjątek MyException
rescue MyException => exception
# obsługa wyjatku MyException
end