Ruby Language
Kontrollfluss
Suche…
Wenn, sonst, sonst und Ende
Ruby bietet die erwarteten if
und else
Ausdrücke für die Verzweigungslogik, die mit dem Schlüsselwort end
beendet werden:
# 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
if
Anweisungen in Ruby Ausdrücke sind, die einen Wert auswerten, und das Ergebnis einer Variablen zugewiesen werden kann:
status = if age < 18
:minor
else
:adult
end
Ruby bietet auch ternäre Operatoren im C-Stil ( siehe Details ), die folgendermaßen ausgedrückt werden können:
some_statement ? if_true : if_false
Dies bedeutet, dass das obige Beispiel mit if-else auch als geschrieben werden kann
status = age < 18 ? :minor : :adult
Darüber hinaus bietet Ruby das Schlüsselwort elsif
das einen Ausdruck akzeptiert, um zusätzliche Verzweigungslogik zu elsif
:
label = if shirt_size == :s
'small'
elsif shirt_size == :m
'medium'
elsif shirt_size == :l
'large'
else
'unknown size'
end
Wenn keine der Bedingungen in einer if
/ elsif
Kette wahr ist und keine else
Klausel vorhanden ist, wird der Ausdruck zu null ausgewertet. Dies kann in der String-Interpolation nützlich sein, da nil.to_s
der leere String ist:
"user#{'s' if @users.size != 1}"
Wahrheits- und Fälschungswerte
In Ruby gibt es genau zwei Werte, die als "falsch" angesehen werden und beim Test als Bedingung für einen if
Ausdruck false zurückgeben. Sie sind:
-
nil
- boolean
false
Alle anderen Werte werden als "wahr" angesehen, einschließlich:
-
0
- numerische Null (Ganzzahl oder anders) -
""
- Leere Zeichenfolgen -
"\n"
- Zeichenfolgen, die nur Leerzeichen enthalten -
[]
- Leere Arrays -
{}
- Leere Hashes
Nehmen Sie zum Beispiel den folgenden Code:
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", {})
Wird ausgegeben:
false is falsy
nil is falsy
0 is truthy
empty string is truthy
\n is truthy
empty array is truthy
empty hash is truthy
während, bis
Eine while
Schleife führt den Block aus, während die angegebene Bedingung erfüllt ist:
i = 0
while i < 5
puts "Iteration ##{i}"
i +=1
end
Ein until
Schleife führt den Block , während die bedingten falsch ist :
i = 0
until i == 5
puts "Iteration ##{i}"
i +=1
end
Inline wenn / wenn nicht
Ein übliches Muster ist ein Inline - oder nachlauf zu verwenden, if
oder unless
:
puts "x is less than 5" if x < 5
Dies ist als bedingter Modifikator bekannt und bietet eine praktische Möglichkeit, einfachen Guard-Code und frühe Rückkehr hinzuzufügen:
def save_to_file(data, filename)
raise "no filename given" if filename.empty?
return false unless data.valid?
File.write(filename, data)
end
Es ist nicht möglich, diesen Modifizierern eine else
Klausel hinzuzufügen. Auch ist es in der Regel nicht empfohlen , bedingte Modifikatoren innerhalb der Hauptlogik zu verwenden - Für komplexen Code sollte man verwenden normale if
, elsif
, else
statt.
es sei denn
Eine häufige Aussage ist if !(some condition)
. Ruby bietet die Alternative der unless
Anweisung an.
Die Struktur entspricht genau einer if
Anweisung, es sei denn, die Bedingung ist negativ. Auch die , unless
Anweisung nicht unterstützt elsif
, aber es unterstützt else
:
# Prints not inclusive
unless 'hellow'.include?('all')
puts 'not inclusive'
end
Fallerklärung
Ruby verwendet das case
Schlüsselwort für switch-Anweisungen.
Wie in den Ruby Docs :
Case-Anweisungen bestehen aus einer optionalen Bedingung, die sich in der Position eines Arguments von
case
zucase
, und null oder mehrwhen
Klauseln. Die erstewhen
Klausel, die mit der Bedingung übereinstimmt (oder der Booleschen Wahrheit entspricht, wenn die Bedingung null ist) "gewinnt", und ihre Code-Zeilengruppe wird ausgeführt. Der Wert der case-Anweisung ist der Wert der erfolgreichenwhen
Klausel odernil
wenn keine solche Klausel vorhanden ist.Eine case-Anweisung kann mit einer
else
Klausel enden. Jedes Mal,when
eine Anweisung mehrere durch Kommas getrennte Kandidatenwerte enthalten kann.
Beispiel:
case x
when 1,2,3
puts "1, 2, or 3"
when 10
puts "10"
else
puts "Some other number"
end
Kürzere Version:
case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end
Der Wert der case
Klausel wird mit jeder when
Klausel mit der Methode ===
(nicht ==
) abgeglichen. Daher kann es mit einer Vielzahl verschiedener Objekttypen verwendet werden.
Eine case
Anweisung kann mit Ranges verwendet werden :
case 17
when 13..19
puts "teenager"
end
Eine case
Anweisung kann mit einer Regexp verwendet werden :
case "google"
when /oo/
puts "word contains oo"
end
Eine case
Anweisung kann mit einem Proc oder Lambda verwendet werden:
case 44
when -> (n) { n.even? or n < 0 }
puts "even or less than zero"
end
Eine case
Anweisung kann mit Klassen verwendet werden :
case x
when Integer
puts "It's an integer"
when String
puts "It's a string"
end
Durch die Implementierung der Methode ===
können Sie eigene Match-Klassen erstellen:
class Empty
def self.===(object)
!object or "" == object
end
end
case ""
when Empty
puts "name was empty"
else
puts "name is not empty"
end
Eine case
Anweisung kann ohne einen entsprechenden Wert verwendet werden:
case
when ENV['A'] == 'Y'
puts 'A'
when ENV['B'] == 'Y'
puts 'B'
else
puts 'Neither A nor B'
end
Eine case
Anweisung hat einen Wert, sodass Sie sie als Methodenargument oder in einer Zuweisung verwenden können:
description = case 16
when 13..19 then "teenager"
else ""
end
Schleifensteuerung mit Pause, Weiter und Wiederholen
Der Ausführungsablauf eines Ruby-Blocks kann mit den Anweisungen break
, next
und redo
gesteuert werden.
break
Die break
Anweisung beendet den Block sofort. Alle verbleibenden Anweisungen im Block werden übersprungen und die Iteration wird beendet:
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
Die next
Anweisung kehrt sofort zum Anfang des Blocks zurück und fährt mit der nächsten Iteration fort. Alle verbleibenden Anweisungen im Block werden übersprungen:
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
Die redo
kehrt sofort zum Anfang des Blocks zurück und wiederholt dieselbe Iteration. Alle verbleibenden Anweisungen im Block werden übersprungen:
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
Iteration
Neben Schleifen arbeiten diese Aussagen mit Enumerable Iterationsverfahren, wie each
und map
:
[1, 2, 3].each do |item|
next if item.even?
puts "Item: #{item}"
end
# Item: 1
# Item: 3
Ergebniswerte blockieren
In den Anweisungen break
und next
kann ein Wert angegeben werden, der als Blockergebniswert verwendet wird:
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
werfen, fangen
Im Gegensatz zu vielen anderen Programmiersprachen beziehen sich die Schlüsselwörter throw
und catch
nicht auf die Ausnahmebehandlung in Ruby.
In Ruby wirken throw
und catch
ein bisschen wie Etiketten in anderen Sprachen. Sie werden verwendet, um den Steuerfluss zu ändern, beziehen sich jedoch nicht auf ein "Fehler" -Konzept wie Ausnahmen sind.
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"
Kontrollfluss mit logischen Anweisungen
Auch wenn dies nicht intuitiv erscheinen mag, können Sie mit logischen Operatoren feststellen, ob eine Anweisung ausgeführt wird oder nicht. Zum Beispiel:
File.exist?(filename) or STDERR.puts "#{filename} does not exist!"
Dadurch wird geprüft, ob die Datei vorhanden ist, und die Fehlernachricht wird nur gedruckt, wenn dies nicht der Fall ist. Die or
-Anweisung ist faul, was bedeutet, dass sie nicht mehr ausgeführt wird, wenn sie sicher ist, ob der Wert wahr oder falsch ist. Sobald festgestellt wird, dass der erste Begriff wahr ist, muss der Wert des anderen Begriffs nicht überprüft werden. Wenn der erste Begriff jedoch falsch ist, muss er den zweiten Begriff überprüfen.
Häufig wird ein Standardwert festgelegt:
glass = glass or 'full' # Optimist!
Dadurch wird der Wert von glass
auf 'voll' gesetzt, wenn es nicht bereits eingestellt ist. Genauer gesagt können Sie die symbolische Version von or
:
glass ||= 'empty' # Pessimist.
Es ist auch möglich, die zweite Anweisung nur auszuführen, wenn die erste Anweisung falsch ist:
File.exist?(filename) and puts "#{filename} found!"
Wiederum and
ist faul, so dass sie die zweite Anweisung nur ausführt, wenn dies erforderlich ist, um einen Wert zu erhalten.
Der Operator or
hat eine niedrigere Priorität als and
. Ebenso ||
hat eine niedrigere Priorität als &&
. Die Symbolformen haben eine höhere Priorität als die Wortformen. Dies ist praktisch, wenn Sie wissen möchten, wann Sie diese Technik mit Zuweisung kombinieren möchten:
a = 1 and b = 2
#=> a==1
#=> b==2
a = 1 && b = 2; puts a, b
#=> a==2
#=> b==2
Beachten Sie, dass der Ruby Style Guide Folgendes empfiehlt :
Die Schlüsselwörter
and
undor
sind verboten. Die minimale zusätzliche Lesbarkeit lohnt sich einfach nicht für die hohe Wahrscheinlichkeit, subtile Fehler einzuführen. Verwenden Sie für boolesche Ausdrücke immer&&
und||
stattdessen. Verwenden Sie für die Flusskontrolleif
undunless
;&&
und||
sind auch akzeptabel, aber weniger klar.
beginnen, ende
Der begin
Block ist eine Kontrollstruktur, die mehrere Anweisungen zusammenfasst.
begin
a = 7
b = 6
a * b
end
Ein begin
Block gibt den Wert der letzten Anweisung im Block zurück. Das folgende Beispiel gibt 3
.
begin
1
2
3
end
Der begin
Block ist nützlich für die bedingte Zuweisung mit dem Operator ||=
, wo möglicherweise mehrere Anweisungen erforderlich sind, um ein Ergebnis zurückzugeben.
circumference ||=
begin
radius = 7
tau = Math::PI * 2
tau * radius
end
Es kann auch mit anderen Blockstrukturen wie kombiniert wird rescue
, ensure
, while
, if
, unless
, etc größere Strömungskontrolle des Programms zur Verfügung zu stellen.
Begin
sind keine Codeblöcke wie { ... }
oder do ... end
; Sie können nicht an Funktionen übergeben werden.
return vs. next: nichtlokale Rückkehr in einem Block
Betrachten Sie dieses abgebrochene Snippet:
def foo
bar = [1, 2, 3, 4].map do |x|
return 0 if x.even?
x
end
puts 'baz'
bar
end
foo # => 0
Man könnte erwarten, dass return
einen Wert für das Blockergebnis der map
ergibt. Der Rückgabewert von foo
wäre also [1, 0, 3, 0]
. Stattdessen gibt return
einen Wert aus der Methode foo
. Beachten Sie, dass baz
nicht gedruckt wird, was bedeutet, dass die Ausführung diese Zeile nie erreicht hat.
next
mit einem Wert macht den Trick. Es wirkt als return
Blockebene.
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]
Ohne return
ist der vom Block zurückgegebene Wert der Wert des letzten Ausdrucks.
Oder-Gleich / Bedingter Zuweisungsoperator (|| =)
Ruby verfügt über einen or-equals-Operator, der die Zuweisung eines Werts zu einer Variablen ermöglicht, und zwar nur dann, wenn diese Variable entweder nil
oder false
.
||= # this is the operator that achieves this.
dieser Operator, wobei die doppelten Pipes oder oder das Gleichheitszeichen die Zuweisung eines Wertes darstellen. Sie denken vielleicht, dass es so etwas darstellt:
x = x || y
Dieses obige Beispiel ist nicht korrekt. Der or-equals-Operator stellt dies tatsächlich dar:
x || x = y
Wenn x
nil
oder false
ergibt, wird x
den Wert von y
zugewiesen und ansonsten unverändert gelassen.
Hier ist ein praktischer Anwendungsfall des Operators or-equals. Stellen Sie sich vor, Sie haben einen Teil Ihres Codes, von dem erwartet wird, dass er eine E-Mail an einen Benutzer sendet. Was tun Sie, wenn aus irgendeinem Grund keine E-Mail für diesen Benutzer vorliegt? Sie könnten so etwas schreiben:
if user_email.nil?
user_email = "[email protected]"
end
Mit dem Operator or-equals können wir den gesamten Code-Code ausschneiden und so eine klare, klare Kontrolle und Funktionalität bieten.
user_email ||= "[email protected]"
Wenn false
ein gültiger Wert ist, muss darauf geachtet werden, dass der Wert nicht versehentlich überschrieben wird:
has_been_run = false
has_been_run ||= true
#=> true
has_been_run = false
has_been_run = true if has_been_run.nil?
#=> false
Ternärer Operator
Ruby hat einen ternären Operator ( ?:
:), Der einen von zwei Werten zurückgibt, die darauf basieren, ob eine Bedingung als wahr bewertet wird:
conditional ? value_if_truthy : value_if_falsy
value = true
value ? "true" : "false"
#=> "true"
value = false
value ? "true" : "false"
#=> "false"
es ist dasselbe wie das Schreiben, if a then b else c end
, obwohl das ternäre bevorzugt wird
Beispiele:
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
Flip-Flop-Operator
Der Flip-Flop-Operator ..
wird zwischen zwei Bedingungen in einer Bedingungsanweisung verwendet:
(1..5).select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 3, 4]
Die Bedingung wird als false
ausgewertet, bis der erste Teil true
. Dann wird es als true
bewertet, bis der zweite Teil true
. Danach wechselt es wieder auf false
.
Dieses Beispiel zeigt, was ausgewählt wird:
[1, 2, 2, 3, 4, 4, 5].select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 2, 3, 4]
Der Flip-Flop-Operator funktioniert nur innerhalb von ifs (einschließlich, unless
) und ternärem Operator. Andernfalls wird es als Bereichsoperator betrachtet.
(1..5).select do |e|
(e == 2) .. (e == 4)
end
# => ArgumentError: bad value for range
Sie kann mehrmals von false
nach true
und zurück wechseln:
((1..5).to_a * 2).select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 3, 4, 2, 3, 4]