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

Wróć Idź do zadań