Sök…


om, elsif, annars och slut

Ruby erbjuder den förväntade if och else uttryck för förgrening logik, avslutas vid end sökord:

# 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

I Ruby, if uttalanden är uttryck som utvärderar till ett värde, och resultatet kan tilldelas en variabel:

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

Ruby erbjuder också C-stil ternära operatörer ( se här för detaljer ) som kan uttryckas som:

some_statement ? if_true : if_false  

Detta betyder att exemplet ovan med if-else också kan skrivas som

status = age < 18 ? :minor : :adult

Dessutom erbjuder Ruby elsif nyckelord som accepterar ett uttryck för att möjliggöra ytterligare grenlogik:

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

Om inget av villkoren i en if / elsif kedja är sanna, och det inte finns någon else klausul, utvärderas uttrycket till noll. Detta kan vara användbart i stränginterpolering, eftersom nil.to_s är den tomma strängen:

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

Sannhets- och falskvärden

I Ruby finns det exakt två värden som betraktas som "förfalskade" och kommer att returnera falska när de testas som ett villkor för ett if uttryck. Dom är:

  • nil
  • boolesk false

Alla andra värden betraktas som "sanningsenliga", inklusive:

  • 0 - numerisk noll (heltal eller på annat sätt)
  • "" - Tomma strängar
  • "\n" - Strängar som endast innehåller blanksteg
  • [] - Tomma matriser
  • {} - Tom hash

Ta till exempel följande 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", {})

Kommer att matas ut:

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

medan, tills

En while slinga exekverar blocket medan det givna villkor är uppfyllt:

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

En until slinga kör blocket medan villkoret är felaktigt:

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

Inline om / om inte

Ett vanligt mönster är att använda en inline, eller släp, if eller om unless :

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

Detta är känt som en villkorlig modifierare och är ett praktiskt sätt att lägga till enkel skyddskod och tidiga returer:

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

  File.write(filename, data)
end

Det är inte möjligt att lägga till en else klausul till dessa modifierare. Är det i allmänhet inte rekommenderas också att använda villkorliga modifierare inuti huvudlogik - För komplex kod bör man använda normal if , elsif , else istället.

såvida inte

Ett vanligt uttalande är if !(some condition) . Ruby erbjuder alternativet till om unless uttalandet.

Strukturen är exakt densamma som ett if uttalande, förutom att villkoret är negativt. Även unless inte uttalandet inte stöd elsif , men det stöd else :

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

Ärende

Ruby använder case sökord för switch uttalanden.

Enligt Ruby Docs :

Ärendeförklaringar består av ett valfritt villkor, som är i positionen för ett argument till case , och noll eller mer when klausuler. Den första when klausulen för att matcha villkoret (eller för att utvärdera till den booleska sanningen, om villkoret är noll) "vinner", och dess kodstans körs. Värdet på ärendeklarationen är värdet på den framgångsrika when klausul, eller nil om det inte finns någon sådan klausul.

Ett ärende kan sluta med en else klausul. Var och en when ett uttalande kan ha flera kandidatvärden, åtskilda med komma.

Exempel:

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

Kortare version:

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

Värdet på case klausulen matchas med varje when klausul använder === metoden (ej == ). Därför kan den användas med en mängd olika typer av objekt.

Ett case kan användas med Ranges :

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

Ett case kan användas med en Regexp :

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

Ett case kan användas med en Proc eller lambda:

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

Ett case kan användas med klasser :

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

Genom att implementera metoden === du skapa dina egna matchningsklasser:

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

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

Ett case kan användas utan värde att matcha mot:

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

Ett case har ett värde, så du kan använda det som ett metodargument eller i en uppgift:

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

Loop-kontroll med paus, nästa och gör om

Flödet av körning av ett Ruby-block kan kontrolleras med uttalanden om break , next och redo om.

break

Den break uttalande kommer att lämna blocket omedelbart. Alla återstående instruktioner i blocket kommer att hoppas över och iterationen slutar:

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 uttalande kommer omedelbart tillbaka till toppen av blocket och fortsätter med nästa iteration. Eventuella återstående instruktioner i blocket kommer att hoppas över:

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

redo kommer omedelbart att återgå till toppen av blocket och försöka samma iteration igen. Eventuella återstående instruktioner i blocket kommer att hoppas över:

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

Förutom slingor, dessa uttalanden arbeta med uppräkningsbar iteration metoder, såsom each och map :

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

# Item: 1
# Item: 3

Blockera värden för resultat

I både break och next påstående kan ett värde anges och kommer att användas som ett blockresultatvärde:

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

kasta, fånga

Till skillnad från många andra programmeringsspråk, de throw och catch är nyckelord inte är relaterade till undantagshantering i Ruby.

I Ruby fungerar throw och catch lite som etiketter på andra språk. De används för att ändra kontrollflödet, men är inte relaterade till ett begrepp "fel" som undantag är.

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"

Kontrollera flödet med logiska uttalanden

Även om det kan verka motsatt, kan du använda logiska operatörer för att avgöra om ett uttal körs eller inte. Till exempel:

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

Detta kontrollerar om filen finns och skrivs bara ut felmeddelandet om den inte gör det. Uttalandet or är uttömt, vilket innebär att det slutar köra när det är säkert vilket värde det är sant eller falskt. Så snart den första termen har visat sig vara sant, finns det inget behov av att kontrollera värdet på den andra termen. Men om den första termen är falsk, måste den kontrollera den andra termen.

En vanlig användning är att ställa in ett standardvärde:

glass = glass or 'full' # Optimist! 

Det sätter värdet på glass till "fullt" om det inte redan är inställt. Mer kortfattat kan du använda den symboliska versionen av or :

glass ||= 'empty' # Pessimist. 

Det är också möjligt att köra det andra uttalandet endast om det första är felaktigt:

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

Återigen, and är lat så det kommer endast att utföra det andra uttalandet om det är nödvändigt för att komma fram till ett värde.

Operatören or operatören har lägre prioritet än and . På liknande sätt || har lägre prioritet än && . Symbolformerna har högre prioritet än ordformerna. Detta är praktiskt att veta när du vill blanda denna teknik med uppdrag:

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

Observera att Ruby Style Guide rekommenderar :

De and och or nyckelorden är förbjudna. Den minimala läsbarheten är bara inte värt den höga sannolikheten för att införa subtila buggar. Använd alltid && och || för booleska uttryck istället. För flödeskontroll, använd if och om unless ; && och || är också acceptabla men mindre tydliga.

börja, slut

begin är en kontrollstruktur som grupperar flera uttalanden.

begin
  a = 7
  b = 6
  a * b
end

En begin blocket kommer att returnera värdet av den sista uttalandet i blocket. Följande exempel kommer att returnera 3 .

begin
  1
  2
  3
end

begin är användbart för villkorad tilldelning med hjälp av ||= operatören där flera uttalanden kan krävas för att returnera ett resultat.

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

Det kan också kombineras med andra blockstrukturer såsom rescue , ensure , while , if , om unless , etc för att ge större kontroll över programflödet.

Begin block är inte kodblock, som { ... } eller do ... end ; de kan inte överföras till funktioner.

retur kontra nästa: icke-lokal retur i ett block

Tänk på det här trasiga utdraget:

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

Man kan förvänta sig att return ger ett värde för map array av blockresultat. Så returvärdet för foo skulle vara [1, 0, 3, 0] . I stället return return ett värde från metoden foo . Lägg märke till att baz inte skrivs ut, vilket innebär att körningen aldrig nådde den raden.

next med ett värde gör tricket. Det fungerar som en blocknivå return .

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]

I avsaknad av en return är värdet som returneras av blocket värdet på det sista uttrycket.

Or-Equals / Conditional allocation operator (|| =)

Ruby har en eller är lika med operatören som gör att ett värde kan tilldelas en variabel om och bara om den variabeln utvärderar antingen nil eller false .

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

denna operatör med de dubbla rören som representerar eller och lika skylten representerar tilldelning av ett värde. Du kanske tror att det representerar något liknande:

 x = x || y

detta exempel ovan är inte korrekt. Operatören or-equals representerar faktiskt detta:

 x || x = y

Om x utvärderar till nil eller false tilldelas x värdet på y och lämnas oförändrat på annat sätt.

Här är ett praktiskt användningsfall av operatören eller likadan. Föreställ dig att du har en del av din kod som förväntas skicka ett e-postmeddelande till en användare. Vad gör du om det av någon anledning inte finns någon e-post för den här användaren. Du kanske skriver något liknande:

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

Med hjälp av operatören or-equals kan vi klippa ut hela koddelen och ge ren, tydlig kontroll och funktionalitet.

 user_email ||= "[email protected]"

I fall där false är ett giltigt värde måste man se till att inte åsidosätta det av misstag:

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

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

Ternary operatör

Ruby har en ternär operatör ( ?: :), Som returnerar ett av två värden baserat på om ett villkor utvärderas som sanningen:

conditional ? value_if_truthy : value_if_falsy

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

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

det är detsamma som att skriva if a then b else c end , även om ternary föredras

Exempel:

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-operatör

Den flip flop operatör .. används mellan två tillstånd i ett villkorligt uttalande:

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

Villkoret utvärderas till false tills den första delen blir true . Därefter utvärderas det till true tills den andra delen blir true . Efter det byter det till false igen.

Detta exempel illustrerar vad som väljs:

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

Flip-flop-operatören fungerar endast inuti ifs (inklusive om unless ) och ternary operator. Annars betraktas det som avståndsoperatören.

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

Det kan växla från false till true och bakåt flera gånger:

((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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow