Szukaj…


jeśli, elsif, else i koniec

Ruby oferuje oczekiwane wyrażenia if i else dla rozgałęzionej logiki, zakończone słowem kluczowym end :

# Simulate flipping a coin
result = [:heads, :tails].sample

if result == :heads
  puts 'The coin-toss came up "heads"'
else
  puts 'The coin-toss came up "tails"'
end

W Ruby, if instrukcje są wyrażeniami, które oceniają na wartość, a wynik można przypisać do zmiennej:

status = if age < 18
           :minor
         else
           :adult
         end

Ruby oferuje także trójskładnikowe operatory w stylu C ( szczegóły tutaj ), które można wyrazić jako:

some_statement ? if_true : if_false  

Oznacza to, że powyższy przykład z użyciem if-else można również zapisać jako

status = age < 18 ? :minor : :adult

Dodatkowo Ruby oferuje słowo kluczowe elsif które akceptuje wyrażenie, aby umożliwić dodatkową logikę rozgałęziania:

label = if shirt_size == :s
          'small'
        elsif shirt_size == :m
          'medium'
        elsif shirt_size == :l
          'large'
        else
          'unknown size'
        end

Jeśli żaden z warunków w łańcuchu if / elsif jest spełniony i nie istnieje żadna else klauzula, wówczas wyrażenie przyjmuje wartość zero. Może to być przydatne w interpolacji ciągów, ponieważ nil.to_s jest pustym ciągiem:

"user#{'s' if @users.size != 1}"

Wartości prawdy i fałszu

W Ruby istnieją dokładnie dwie wartości, które są uważane za „falsy” i zwrócą wartość false, gdy zostaną przetestowane jako warunek dla wyrażenia if . Oni są:

  • nil
  • boolean false

Wszystkie pozostałe wartości są uważane za „prawdziwe”, w tym:

  • 0 - zero liczbowe (liczba całkowita lub inna)
  • "" - Puste ciągi
  • "\n" - Ciągi zawierające tylko białe znaki
  • [] - Puste tablice
  • {} - Opróżnij skróty

Weźmy na przykład następujący kod:

def check_truthy(var_name, var)
  is_truthy = var ? "truthy" : "falsy"
  puts "#{var_name} is #{is_truthy}"
end

check_truthy("false", false)
check_truthy("nil", nil)
check_truthy("0", 0)
check_truthy("empty string", "")
check_truthy("\\n", "\n")
check_truthy("empty array", [])
check_truthy("empty hash", {})

Wyjdzie:

false is falsy
nil is falsy
0 is truthy
empty string is truthy
\n is truthy
empty array is truthy
empty hash is truthy

podczas, dopóki

while pętla wykonuje blok podczas gdy dany warunek jest spełniony:

i = 0
while i < 5
  puts "Iteration ##{i}"
  i +=1
end

until pętli wykonuje blok natomiast uwarunkowane jest fałszywe:

i = 0
until i == 5
  puts "Iteration ##{i}"
  i +=1
end

Wbudowany jeśli / o ile

Typowym wzorcem jest użycie wstawki lub końca, if lub unless :

puts "x is less than 5" if x < 5

Jest to znane jako modyfikator warunkowy i jest przydatnym sposobem dodania prostego kodu ochronnego i wczesnych zwrotów:

def save_to_file(data, filename)
  raise "no filename given" if filename.empty?
  return false unless data.valid?

  File.write(filename, data)
end

Nie można dodać klauzuli else do tych modyfikatorów. Ponadto generalnie nie zaleca się używania modyfikatorów warunkowych w głównej logice - w przypadku złożonego kodu należy użyć normalnego if , elsif , else zamiast tego.

chyba że

Powszechnym stwierdzeniem jest if !(some condition) . Ruby oferuje alternatywę dla instrukcji unless .

Struktura jest dokładnie taka sama jak instrukcja if , ale warunek jest ujemny. Ponadto, unless oświadczenie nie obsługuje elsif ale to nie obsługuje else :

# Prints not inclusive
unless 'hellow'.include?('all')
  puts 'not inclusive'
end

Oświadczenie o sprawie

Ruby używa słowa kluczowego case do instrukcji switch.

Zgodnie z Ruby Docs :

Instrukcje case składają się z warunku opcjonalnego, który znajduje się w pozycji argumentu case , i zero lub więcej, when klauzulami. Pierwsza klauzula when pasująca do warunku (lub do oceny logicznej prawdy, jeśli warunek jest pusty) „wygrywa”, a sekcja kodu jest wykonywana. Wartość instrukcji case jest wartością klauzuli pomyślnego when lub nil jeśli takiej klauzuli nie ma.

Instrukcja case może kończyć się klauzulą else . Za każdym razem, when instrukcja może mieć wiele wartości kandydujących, oddzielonych przecinkami.

Przykład:

case x
when 1,2,3
  puts "1, 2, or 3"
when 10
  puts "10"
else
  puts "Some other number"
end

Krótsza wersja:

case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end

Wartość klauzuli case jest dopasowywana do każdej klauzuli when przy użyciu metody === (nie == ). Dlatego można go używać z różnymi rodzajami obiektów.

case oświadczenie może być używany z zakresów :

case 17
when 13..19
  puts "teenager"
end

case oświadczenie może być używany z RegExp :

case "google"
when /oo/
  puts "word contains oo"
end

Instrukcja case może być używana z Proc lub lambda:

case 44
when -> (n) { n.even? or n < 0 }
  puts "even or less than zero"
end

Instrukcja case może być używana z klasami :

case x
when Integer
  puts "It's an integer"
when String
  puts "It's a string"
end

Wdrażając metodę === możesz stworzyć własne klasy dopasowania:

class Empty
  def self.===(object)
    !object or "" == object
  end
end

case ""
when Empty
  puts "name was empty"
else
  puts "name is not empty"
end

Instrukcja case może być używana bez wartości do dopasowania do:

case
when ENV['A'] == 'Y'
  puts 'A'
when ENV['B'] == 'Y'
  puts 'B'
else
  puts 'Neither A nor B'
end

Instrukcja case ma wartość, więc możesz użyć jej jako argumentu metody lub w przypisaniu:

description = case 16
              when 13..19 then "teenager"
              else ""
              end

Kontrola pętli za pomocą break, next i redo

Przepływ wykonania bloku Ruby może być kontrolowany za pomocą instrukcji break , next i redo .

break

Instrukcja break natychmiast opuści blok. Wszelkie pozostałe instrukcje w bloku zostaną pominięte, a iteracja zakończy się:

actions = %w(run jump swim exit macarena)
index = 0

while index < actions.length
  action = actions[index]

  break if action == "exit"

  index += 1
  puts "Currently doing this action: #{action}"
end

# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim

next

next instrukcja natychmiast powróci na górę bloku i przejdzie do następnej iteracji. Wszelkie pozostałe instrukcje w bloku zostaną pominięte:

actions = %w(run jump swim rest macarena)
index = 0

while index < actions.length
  action = actions[index]
  index += 1

  next if action == "rest"

  puts "Currently doing this action: #{action}"
end

# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
# Currently doing this action: macarena

redo

Instrukcja redo natychmiast powróci na górę bloku i powtórzy tę samą iterację. Wszelkie pozostałe instrukcje w bloku zostaną pominięte:

actions = %w(run jump swim sleep macarena)
index = 0
repeat_count = 0

while index < actions.length
  action = actions[index]
  puts "Currently doing this action: #{action}"

  if action == "sleep"
    repeat_count += 1
    redo if repeat_count < 3
  end

  index += 1
end

# Currently doing this action: run
# Currently doing this action: jump
# Currently doing this action: swim
# Currently doing this action: sleep
# Currently doing this action: sleep
# Currently doing this action: sleep
# Currently doing this action: macarena

Enumerable iteracja

Oprócz pętli, te instrukcje działają z metodami iteracji Enumerable, takimi jak each i map :

[1, 2, 3].each do |item|
  next if item.even?
  puts "Item: #{item}"
end

# Item: 1
# Item: 3

Blokuj wartości wyników

W obu instrukcjach break i next można podać wartość, która zostanie użyta jako wynik wyniku bloku:

even_value = for value in [1, 2, 3]
  break value if value.even?
end

puts "The first even value is: #{even_value}"

# The first even value is: 2

rzucać, łapać

W przeciwieństwie do wielu innych języków programowania, słowa kluczowe „ throw i catch nie są powiązane z obsługą wyjątków w Rubim.

W Ruby throw i catch działają trochę jak etykiety w innych językach. Służą do zmiany przepływu sterowania, ale nie są związane z pojęciem „błędu”, jak w przypadku wyjątków.

catch(:out) do
  catch(:nested) do
    puts "nested"
  end

  puts "before"
  throw :out
  puts "will not be executed"
end
puts "after"
# prints "nested", "before", "after"

Kontroluj przepływ za pomocą instrukcji logicznych

Chociaż może się to wydawać sprzeczne z intuicją, można użyć operatorów logicznych do ustalenia, czy instrukcja jest uruchamiana. Na przykład:

File.exist?(filename) or STDERR.puts "#{filename} does not exist!"

Spowoduje to sprawdzenie, czy plik istnieje, i wydrukuje komunikat o błędzie, jeśli nie istnieje. Instrukcja or jest leniwa, co oznacza, że przestanie działać, gdy będzie pewne, czy jej wartość jest prawdą czy fałszem. Gdy tylko pierwszy warunek okaże się prawdziwy, nie ma potrzeby sprawdzania wartości drugiego terminu. Ale jeśli pierwszy termin jest fałszywy, musi sprawdzić drugi termin.

Typowym zastosowaniem jest ustawienie wartości domyślnej:

glass = glass or 'full' # Optimist! 

To ustawia wartość glass na „pełny”, jeśli nie jest jeszcze ustawiona. Mówiąc dokładniej, możesz użyć symbolicznej wersji or :

glass ||= 'empty' # Pessimist. 

Możliwe jest również uruchomienie drugiej instrukcji tylko wtedy, gdy pierwsza jest fałszywa:

File.exist?(filename) and puts "#{filename} found!"

Ponownie and jest leniwy, więc wykona drugie polecenie tylko w razie potrzeby, aby uzyskać wartość.

Operator or ma niższy priorytet niż and . Podobnie || ma niższy priorytet niż && . Formy symboli mają wyższy priorytet niż formy słów. Warto wiedzieć, kiedy chcesz połączyć tę technikę z zadaniem:

a = 1 and b = 2
#=> a==1
#=> b==2
a = 1 && b = 2; puts a, b
#=> a==2
#=> b==2

Zauważ, że Ruby Style Guide zaleca :

and i or słowa kluczowe są zakazane. Minimalna dodana czytelność nie jest po prostu warta wysokiego prawdopodobieństwa wprowadzenia subtelnych błędów. W przypadku wyrażeń boolowskich zawsze używaj && i || zamiast. Do kontroli przepływu użyj, if i o unless ; i && i || są również do przyjęcia, ale mniej jasne.

początek, koniec

begin blok jest strukturą sterowania, który grupuje wiele wypowiedzi.

begin
  a = 7
  b = 6
  a * b
end

begin blok zwróci wartość ostatniej instrukcji w bloku. Poniższy przykład zwróci 3 .

begin
  1
  2
  3
end

begin blok jest użyteczny do przypisania warunkowego pomocą ||= operatora, gdzie może być wymagany wielu instrukcji zwraca wynik.

circumference ||=
  begin
    radius = 7
    tau = Math::PI * 2
    tau * radius
  end

Można go również łączyć z innymi strukturami blokowymi, takimi jak rescue , ensure , while , if , unless itd., Aby zapewnić lepszą kontrolę nad przebiegiem programu.

Bloki Begin nie są blokami kodu, takimi jak { ... } lub do ... end ; nie można ich przekazać do funkcji.

return vs. next: nielokalny zwrot w bloku

Rozważ ten uszkodzony fragment:

def foo
  bar = [1, 2, 3, 4].map do |x|
    return 0 if x.even?
    x
  end
  puts 'baz'
  bar
end
foo # => 0

Można oczekiwać, że return wartość dla tablicy wyników bloków map . Zatem zwracana wartość foo wynosiłaby [1, 0, 3, 0] . Zamiast tego return zwraca wartość z metody foo . Zauważ, że baz nie jest drukowany, co oznacza, że wykonanie nigdy nie osiągnęło tej linii.

next z wartością robi lewę. Działa jak return poziomie bloku.

def foo
  bar = [1, 2, 3, 4].map do |x|
    next 0 if x.even?
    x
  end
  puts 'baz'
  bar
end
foo # baz
    # => [1, 0, 3, 0]

W przypadku braku return wartość zwracana przez blok jest wartością jego ostatniego wyrażenia.

Operator przypisania równego lub warunkowego (|| =)

Ruby ma operator or-equals, który pozwala na przypisanie wartości zmiennej tylko wtedy, gdy zmienna ma wartość nil lub false .

 ||= # this is the operator that achieves this. 

ten operator z podwójnymi potokami reprezentującymi lub i znakiem równości reprezentującym przypisanie wartości. Możesz myśleć, że reprezentuje coś takiego:

 x = x || y

ten powyższy przykład jest niepoprawny. Operator or-equals faktycznie reprezentuje to:

 x || x = y

Jeśli x wartość nil lub false wówczas x ma przypisaną wartość y , w przeciwnym razie pozostaje niezmienione.

Oto praktyczny przypadek użycia operatora or-equals. Wyobraź sobie, że masz część kodu, która ma wysłać wiadomość e-mail do użytkownika. Co robisz, jeśli z jakiegokolwiek powodu nie ma wiadomości e-mail dla tego użytkownika. Możesz napisać coś takiego:

 if user_email.nil?
    user_email = "[email protected]"
 end

Za pomocą operatora or-equals możemy wyciąć cały fragment kodu, zapewniając czystą, jasną kontrolę i funkcjonalność.

 user_email ||= "[email protected]"

W przypadkach, w których false jest prawidłową wartością, należy zachować ostrożność, aby przypadkowo jej nie zastąpić:

has_been_run = false
has_been_run ||= true
#=> true

has_been_run = false
has_been_run = true if has_been_run.nil?
#=> false

Operator trójskładnikowy

Ruby ma operator trójskładnikowy ( ?: :), Który zwraca jedną z dwóch wartości na podstawie tego, czy warunek zostanie oceniony jako prawdziwy:

conditional ? value_if_truthy : value_if_falsy

value = true
value ? "true" : "false"
#=> "true"

value = false
value ? "true" : "false"
#=> "false"

jest to to samo, co pisanie, if a then b else c end , choć trójka jest preferowana

Przykłady:

puts (if 1 then 2 else 3 end) # => 2

puts 1 ? 2 : 3                # => 2

x = if 1 then 2 else 3 end
puts x                        # => 2

Operator Flip-Flop

Operator flip-flop .. jest używany między dwoma warunkami w instrukcji warunkowej:

(1..5).select do |e|
  e if (e == 2) .. (e == 4)
end
# => [2, 3, 4]

Warunek ma wartość false dopóki pierwsza część nie zostanie true . Następnie ocenia się na true druga część stanie się true . Następnie ponownie zmienia się na false .

Ten przykład ilustruje, co jest wybierane:

[1, 2, 2, 3, 4, 4, 5].select do |e|
  e if (e == 2) .. (e == 4)
end
# => [2, 2, 3, 4]

Operator flip-flop działa tylko wewnątrz ifs (włączając unless ) i operator trójskładnikowy. W przeciwnym razie jest uważany za operatora zasięgu.

(1..5).select do |e|
  (e == 2) .. (e == 4)
end
# => ArgumentError: bad value for range

Może wielokrotnie przełączać się z false na true i wstecz:

((1..5).to_a * 2).select do |e|
  e if (e == 2) .. (e == 4)
end
# => [2, 3, 4, 2, 3, 4] 


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow