Ruby'de bir switch deyimi nasıl yazılır


Yanıtlar:


2670

Ruby bunun yerine caseifadeyi kullanır.

case x
when 1..5
  "It's between 1 and 5"
when 6
  "It's 6"
when "foo", "bar"
  "It's either foo or bar"
when String
  "You passed a string"
else
  "You gave me #{x} -- I have no idea what to do with that."
end

Ruby, whenyan tümcedeki nesneyi işleç casekullanarak yan tümcedeki nesneyle karşılaştırır ===. Örneğin, 1..5 === xdeğil x === 1..5.

Bu, whenyukarıda görüldüğü gibi sofistike hükümlere izin verir . Sıradağlar, sınıflar ve her türlü şey eşitlikten ziyade test edilebilir.

Aksine switchdiğer birçok dilde ifadeleri, Ruby'nin caseyok sonbahar-through böylece her bitirmek için gerek yoktur, whenbir ile break. Ayrıca, tek bir whencümlede birden çok eşleşme belirtebilirsiniz when "foo", "bar".


12
Ayrıca, iletilen argüman üzerinde normal ifade de yapabilirsiniz: when / thisisregex / next line "Bu bulunan eşleşme numarası 1 # {$ 1}" sonunu koyar
Automatico

8
Ayrıca dikkat etmeniz gereken, whenve returnsatırını aynı satıra koyarak kodunuzu kısaltabilirsiniz :when "foo" then "bar"
Alexander - Monica'yı eski

9
Önemli: Diğer switchbirçok dilde yer alan ifadelerin aksine , Ruby'nin düşmesicase YOKTUR , bu yüzden her birini a ile bitirmeye gerek yoktur . whenbreak
janniks

3
Çok fazla oy henüz anahtar kelime bir söz değil then. Lütfen diğer cevaplara da bakınız.
Clint Pachl

442

case...whensınıfları işlerken beklenmedik bir şekilde davranır. Bunun nedeni ===operatörü kullanmasıdır.

Bu operatör değişmez değerlerle beklendiği gibi çalışır, ancak sınıflarla çalışmaz:

1 === 1           # => true
Fixnum === Fixnum # => false

Bu, case ... whenbir nesnenin sınıfının üzerinde yapmak istiyorsanız , bunun işe yaramayacağı anlamına gelir:

obj = 'hello'
case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string or number')
end

"Bir dize veya sayı değil" yazdıracak.

Neyse ki, bu kolayca çözülebilir. ===Döndürecek şekilde operatör tanımlanmıştır truebir sınıf ile kullanmak ve ikinci işlenen olarak bu sınıfın bir örneğini temin edin:

Fixnum === 1 # => true

Kısacası, yukarıdaki kod aşağıdakileri kaldırarak düzeltilebilir .class:

obj = 'hello'
case obj  # was case obj.class
when String
  print('It is a string')
when Fixnum
  print('It is a number')
else
  print('It is not a string or number')
end

Bugün bu soruyu bir cevap ararken vurdum ve bu ilk görünen sayfaydı, bu yüzden aynı durumdaki başkaları için yararlı olacağını düşündüm.


obj = 'merhaba'; 'merhaba' sonra "merhaba" sonunu koyar
Sugumar Venkatesan

İçinde yer .classalmak not etmek ilginç, teşekkürler. Tabii ki, bu tamamen uygun bir davranış (gerçi bunun yazdırmayı düşünmenin yaygın bir hata olabileceğini görebiliyordum It is a string) ... nesnenin kendisini değil, keyfi bir nesnenin sınıfını test ediyorsunuz . Yani, örneğin: case 'hello'.class when String then "String!" when Class then "Class!" else "Something else" endsonuçlardan: "Class!"Bu aynı şekilde çalışır 1.class, {}.classvb bırakarak .class, biz olsun "String!"veya "Something else"bu çeşitli değerler için.
19:14

219

caseRuby'de kullanılarak yapılır . Ayrıca Wikipedia'da " Geçiş ifadesi " konusuna bakın .

Alıntı:

case n
when 0
  puts 'You typed zero'
when 1, 9
  puts 'n is a perfect square'
when 2
  puts 'n is a prime number'
  puts 'n is an even number'
when 3, 5, 7
  puts 'n is a prime number'
when 4, 6, 8
  puts 'n is an even number'
else
  puts 'Only single-digit numbers are allowed'
end

Başka bir örnek:

score = 70

result = case score
   when 0..40 then "Fail"
   when 41..60 then "Pass"
   when 61..70 then "Pass with Merit"
   when 71..100 then "Pass with Distinction"
   else "Invalid Score"
end

puts result

Kindle'daki Ruby Programlama Dili'nin (1. Baskı, O'Reilly) yaklaşık 123. sayfasında then, whencümleleri takip eden anahtar kelimenin bir satırsonu veya noktalı virgülle ( if then elsesözdiziminde olduğu gibi ) değiştirilebileceği belirtiliyor. (Ruby 1.8 de yerine iki nokta üst üste işaretine izin verir then, ancak bu sözdizimine artık Ruby 1.9'da izin verilmez.)


38
when (-1.0/0.0)..-1 then "Epic fail"
Andrew Grimm

Kullandığım yanıt bu, çünkü bir vaka anahtarının sonuçlarına göre bir değişken tanımlıyorum. type = #{score}Her satırı söylemek yerine , yaptığınızı kopyalayabilirim. Çok daha zarif Ben de tek gömlekleri daha iyi seviyorum (mümkünse)
onebree

Bunun cevabın özü ile ilgisi olmadığını biliyorum, ancak 4 aynı zamanda mükemmel bir kare.
Nick Moore

109

vaka ... ne zaman

Chuck'ın cevabına daha fazla örnek eklemek için :

Parametre ile:

case a
when 1
  puts "Single value"
when 2, 3
  puts "One of comma-separated values"
when 4..6
  puts "One of 4, 5, 6"
when 7...9
  puts "One of 7, 8, but not 9"
else
  puts "Any other thing"
end

Parametre olmadan:

case
when b < 3
  puts "Little than 3"
when b == 3
  puts "Equal to 3"
when (1..10) === b
  puts "Something in closed range of [1..10]"
end

Lütfen, kikito'nun uyardığı " Ruby'de bir anahtar deyimi nasıl yazılır? "


Teşekkürler, bu bir satırda birden fazla seçenek olması için yararlı oldu. or
Kullanmaya

73

Birçok programlama dili, özellikle de C'den türetilmiş olanlar, Geçiş Anahtarı için destek sağlar . Ruby'de aynı şeyi yapmanın en iyi yolunu arıyordum ve başkaları için yararlı olabileceğini düşündüm:

C-benzeri dillerde, geçiş tipik olarak şöyle görünür:

switch (expression) {
    case 'a':
    case 'b':
    case 'c':
        // Do something for a, b or c
        break;
    case 'd':
    case 'e':
        // Do something else for d or e
        break;
}

Ruby'de aynı şey şu şekilde elde edilebilir:

case expression
when 'a', 'b', 'c'
  # Do something for a, b or c
when 'd', 'e'
  # Do something else for d or e
end

Bu kesinlikle eşdeğer değildir, çünkü veya 'ya 'a'düşmeden önce bir kod bloğu yürütmek mümkün değildir , ancak çoğunlukla aynı şekilde yararlı olacak kadar benzer buluyorum.'b''c'


72

Ruby 2.0'da lambdas'ı caseaşağıdaki gibi ifadelerde de kullanabilirsiniz :

is_even = ->(x) { x % 2 == 0 }

case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end

Özel bir Yapı kullanarak kendi karşılaştırıcılarınızı da kolayca oluşturabilirsiniz ===

Moddable = Struct.new(:n) do
  def ===(numeric)
    numeric % n == 0
  end
end

mod4 = Moddable.new(4)
mod3 = Moddable.new(3)

case number
when mod4 then puts 'multiple of 4'
when mod3 then puts 'multiple of 3'
end

(" Proclar Ruby 2.0'daki vaka ifadeleriyle kullanılabilir mi? "

Veya tam bir sınıfla:

class Vehicle
  def ===(another_vehicle)
    self.number_of_wheels == another_vehicle.number_of_wheels
  end
end

four_wheeler = Vehicle.new 4
two_wheeler = Vehicle.new 2

case vehicle
when two_wheeler
  puts 'two wheeler'
when four_wheeler
  puts 'four wheeler'
end

(" Bir Ruby Case İfadesi Nasıl Çalışır ve Bununla Ne Yapabilirsiniz " örneğinden alınmıştır .)


52

Bir dize türü bulma gibi normal ifadeler kullanabilirsiniz:

case foo
when /^(true|false)$/
   puts "Given string is boolean"
when /^[0-9]+$/ 
   puts "Given string is integer"
when /^[0-9\.]+$/
   puts "Given string is float"
else
   puts "Given string is probably string"
end

Ruby casebunun için eşitlik işleneni kullanacak ===(teşekkürler @JimDeville). Daha fazla bilgi " Ruby Operatörleri " nde bulunabilir . Bu, @mmdemirbas örneği (parametre olmadan) kullanılarak da yapılabilir, sadece bu yaklaşım bu tür durumlar için daha temizdir.



33

Denir caseve beklediğiniz gibi çalışır, ayrıca ===testleri uygulayan çok daha eğlenceli şeyler .

case 5
  when 5
    puts 'yes'
  else
    puts 'else'
end

Şimdi biraz eğlenmek için:

case 5 # every selector below would fire (if first)
  when 3..7    # OK, this is nice
  when 3,4,5,6 # also nice
  when Fixnum  # or
  when Integer # or
  when Numeric # or
  when Comparable # (?!) or
  when Object  # (duhh) or
  when Kernel  # (?!) or
  when BasicObject # (enough already)
    ...
end

Ve ortaya çıkıyorsa, / else zincirini (yani, testler ortak bir değişkeni içermese bile) case, ilk caseparametreyi bırakarak ve sadece ilk eşleşmenin istediğiniz şey olduğu ifadeleri yazarak değiştirebilirsiniz.

case
  when x.nil?
    ...
  when (x.match /'^fn'/)
    ...
  when (x.include? 'substring')
    ...
  when x.gsub('o', 'z') == 'fnzrq'
    ...
  when Time.now.tuesday?
    ...
end

23

Ruby, caseswitch deyimlerini yazmak için kullanır .

Gereğince casebelgeler:

Vaka ifadeleri, bir argüman konumunda olan isteğe bağlı bir koşul caseve sıfır veya daha fazla whencümleden oluşur. whenKoşulla eşleşen ilk koşul (veya koşul boşsa Boole gerçeğini değerlendirmek için) “kazanır” ve kod stanzaları yürütülür. Vaka ifadesinin değeri, başarılı whenmaddenin veya nilböyle bir maddenin bulunmadığı değerdir .

Vaka ifadesi bir elsecümle ile sona erebilir . Her whenifadenin virgülle ayrılmış birden fazla aday değeri olabilir.

Misal:

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

Kısa versiyon:

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

Ve " Ruby'nin durum bildirimi - ileri teknikler " olarak Ruby case;

Aralıklarla kullanılabilir :

case 5
when (1..10)
  puts "case statements match inclusion in a range"
end

## => "case statements match inclusion in a range"

Regex ile kullanılabilir :

case "FOOBAR"
when /BAR$/
  puts "they can match regular expressions!"
end

## => "they can match regular expressions!"

Procs ve Lambdas ile kullanılabilir :

case 40
when -> (n) { n.to_s == "40" }
  puts "lambdas!"
end

## => "lambdas"

Ayrıca, kendi maç sınıflarınızla birlikte kullanılabilir:

class Success
  def self.===(item)
    item.status >= 200 && item.status < 300
  end
end

class Empty
  def self.===(item)
    item.response_size == 0
  end
end

case http_response
when Empty
  puts "response was empty"
when Success
  puts "response was a success"
end

22

Durumunuza bağlı olarak, bir karma yöntem kullanmayı tercih edebilirsiniz.

Uzun bir whens listesi varsa ve her birinin karşılaştırılacak bir somut değeri varsa (bir aralık değil), bir yöntem karma değeri bildirmek ve daha sonra ilgili yöntemi karmadan böyle çağırmak daha etkili olacaktır.

# Define the hash
menu = {a: :menu1, b: :menu2, c: :menu2, d: :menu3}

# Define the methods
def menu1
  puts 'menu 1'
end

def menu2
  puts 'menu 2'
end

def menu3
  puts 'menu3'
end

# Let's say we case by selected_menu = :a
selected_menu = :a

# Then just call the relevant method from the hash
send(menu[selected_menu])

21

Yana switch caseher zaman tek nesnesi döndüren, biz Sonuçlarını doğrudan yazdırabilirsiniz:

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end

20

Çok değerli zaman ve değersiz durum:

print "Enter your grade: "
grade = gets.chomp
case grade
when "A", "B"
  puts 'You pretty smart!'
when "C", "D"
  puts 'You pretty dumb!!'
else
  puts "You can't even use a computer!"
end

Ve burada düzenli bir ifade çözümü:

print "Enter a string: "
some_string = gets.chomp
case
when some_string.match(/\d/)
  puts 'String has numbers'
when some_string.match(/[a-zA-Z]/)
  puts 'String has letters'
else
  puts 'String has no numbers or letters'
end

2
neden sadece case some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end(burada ,satırsonu anlamına gelir)
Doorknob

2
oh, ve ilk kısım zaten bu cevapta kapsanmıştır ve birçok cevap zaten normal ifadeden bahsetmektedir. Açıkçası, bu cevap yeni bir şey eklemiyor ve ben silmek için oy veriyorum ve oy veriyorum.
Doorknob

@DoorknobofSnow Bu, anahtar durumunda Regex çözümünü ve virgülle ayrılmış değerleri kullanabileceğinizi göstermek içindir. Çözümün neden bu kadar çok ağrı verdiğinden emin değilim.
123

yani onlar "F", yasal bir not varsa, onların hatası kodunuzu bir durumda eksik?
Mike Graf

Bunun mizahını seviyorum ve dizeleri bir dava ile eşleştirebileceğinizi gösteriyor.
zımpara

13

caseRuby'de iki farklı şekilde ifade yazabilirsiniz :

  1. Bir dizi ififadeye benzer
  2. Yanında bir hedef belirleyin caseve her bir whenmadde hedefle karşılaştırılır.
age = 20
case 
when age >= 21
puts "display something"
when 1 == 0
puts "omg"
else
puts "default condition"
end

veya:

case params[:unknown]
when /Something/ then 'Nothing'
when /Something else/ then 'I dont know'
end

Kodunuz soruyu cevaplayabilse de, kodunuzun ne yaptığı ve ilk sorunu nasıl çözdüğü hakkında en azından kısa bir açıklama eklemelisiniz .
user1438038

Gelecekte bu ipucunu ele alacağım.
ysk

10

Bunu daha doğal bir şekilde yapabilirsiniz,

case expression
when condtion1
   function
when condition2
   function
else
   function
end

9

Çok büyük cevaplar ama bir factoid ekleyeceğini düşündüm .. Nesneleri karşılaştırmaya çalışıyorsanız (Sınıflar) bir uzay gemisi yöntemi (şaka değil) olduğundan emin olun veya nasıl karşılaştırıldığını anlayın

Ruby Eşitliği ve Nesne Karşılaştırması ” konuyla ilgili güzel bir tartışma.


7
Referans olarak, <=>karşılaştırmanın sırasıyla daha küçük, eşit, daha büyük veya karşılaştırılamaz olarak dönmesine bağlı olarak -1, 0, 1 veya nil döndürmek için kullanılan "uzay gemisi" yöntemi kullanılır. Ruby'nin Karşılaştırılabilir modül belgeleri bunu açıklıyor.
Tin Man

7

Yukarıdaki cevapların çoğunda belirtildiği gibi, ===operatör case/ whenifadeleri altında kullanılır .

İşte bu operatör hakkında ek bilgi:

Vaka eşitliği operatörü: ===

Ruby'nin String, Range ve Regexp gibi yerleşik sınıflarının birçoğu ==="case-equality", "triple equals" veya "threequals" olarak da bilinen operatörün kendi uygulamalarını sağlar . Her sınıfta farklı uygulandığından, çağrıldığı nesnenin türüne bağlı olarak farklı davranacaktır. Genel olarak, sağdaki "sol" nesnesinin "veya" nesnesinin "üyesi" ise doğru değerini döndürür. Örneğin, bir nesnenin bir sınıfın (ya da alt sınıflarından birinin) bir örneği olup olmadığını test etmek için kullanılabilir.

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

Aynı sonuç, muhtemelen iş için en uygun olan diğer yöntemlerle is_a?ve gibi elde edilebilir instance_of?.

Menzil Uygulaması ===

Ne zaman ===operatör bir dizi nesne üzerinde çağrılır sağda değer soldaki aralığa giriyorsa, bu doğru döner.

(1..4) === 3  # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6  # Output: => false

("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false

===Operatörün ===sol nesnenin yöntemini çağırdığını unutmayın . Yani buna (1..4) === 3eşdeğerdir (1..4).=== 3. Başka bir deyişle, sol taraftaki işlenenin sınıfı, ===yöntemin hangi uygulamasına çağrılacağını tanımlayacaktır , bu nedenle işlenen konumları birbirinin yerine kullanılamaz.

Regexp Uygulaması ===

Sağdaki dize, soldaki normal ifadeyle eşleşiyorsa true değerini döndürür.

/zen/ === "practice zazen today"  # Output: => true
# is similar to
"practice zazen today"=~ /zen/

Yukarıdaki iki örnek arasındaki tek fark, bir eşleşme olduğunda ===true =~değerini ve Ruby'de doğru bir değer olan bir tamsayıyı döndürmesidir. Yakında buna geri döneceğiz.


5
puts "Recommend me a language to learn?"
input = gets.chomp.downcase.to_s

case input
when 'ruby'
    puts "Learn Ruby"
when 'python'
    puts "Learn Python"
when 'java'
    puts "Learn Java"
when 'php'
    puts "Learn PHP"
else
    "Go to Sleep!"
end

1
Bunun neden tercih edilen çözüm olduğunu açıklar ve nasıl çalıştığını açıklarsanız daha fazla yardımcı olur. Sadece kod sağlamakla kalmayıp eğitmek istiyoruz.
Tin Man


1

Kullanmaya başladım:

a = "secondcase"

var_name = case a
  when "firstcase" then "foo"
  when "secondcase" then "bar"
end

puts var_name
>> "bar"

Bazı durumlarda kompakt koda yardımcı olur.


1
Bunun gibi kodlar genellikle Hashbir caseifade yerine a kullanılarak yapılmalıdır .
Tom Lord

Bu anahtar büyüdüğünde bir karma kullanmak daha hızlı olurdu.
Tin Man

1

Ortamınızdaki düzenli ifadeler için destek yok mu? Örneğin Shopify Script Editor (Nisan 2018):

[Hata]: başlatılmamış sabit RegExp

Daha önce burada ve burada ele alınan yöntemlerin bir kombinasyonunu izleyen bir geçici çözüm :

code = '!ADD-SUPER-BONUS!'

class StrContains
  def self.===(item)
    item.include? 'SUPER' or item.include? 'MEGA' or\
    item.include? 'MINI' or item.include? 'UBER'
  end
end

case code.upcase
when '12345PROMO', 'CODE-007', StrContains
  puts "Code #{code} is a discount code!"
when '!ADD-BONUS!'
  puts 'This is a bonus code!'
else
  puts 'Sorry, we can\'t do anything with the code you added...'
end

orSınıf yöntemi deyiminde s kullandığımdan ||daha yüksek önceliğe sahip .include?. Eğer bir yakut-nazi iseniz , lütfen (item.include? 'A') || ...bunun yerine kullandığımı hayal edin . repl.it testi.


1

Bir cümledeki virgül ( ,) öğesini vurgulamak önemlidir when. ||Bir ifdeyim olarak hareket eder , yani, cümlenin sınırlandırılmış ifadeleri arasında VE karşılaştırması değil, OR karşılaştırması yapar . Aşağıdaki vaka bildirimlerine bakın:when

x = 3
case x
  when 3, x < 2 then 'apple'
  when 3, x > 2 then 'orange'
end
 => "apple"

x2'den az değil, ancak dönüş değeri "apple". Neden? Çünkü 3'dü xve ',`` acts as an|| , it did not bother to evaluate the expressionx <2 '.

Bir VE yapmak için aşağıdaki gibi bir şey yapabileceğinizi düşünebilirsiniz , ancak işe yaramaz:

case x
  when (3 && x < 2) then 'apple'
  when (3 && x > 2) then 'orange'
end
 => nil 

Çünkü çalışmıyor (3 && x > 2)true değerlendirir ve Ruby Gerçek değerini alır ve karşılaştırır xile ===beri, doğru değil, x3'tür.

Bir &&karşılaştırma yapmak için / block casegibi davranmanız gerekir :ifelse

case
  when x == 3 && x < 2 then 'apple'
  when x == 3 && x > 2 then 'orange'
end

Ruby Programlama Dili kitabında Matz, bu son formun basit (ve nadiren kullanılan) form olduğunu ve bunun if/ elsif/ için alternatif bir sözdiziminden başka bir şey olmadığını söylüyor else. Ancak, nadiren kullanılsın veya kullanılmasın, &&belirli bir whenfıkra için birden fazla ifade eklemenin başka bir yolunu görmüyorum .


Bu benim için iyi bir kodlama tarzı gibi görünmüyor. Nadir bir alternatif sözdizimi kullanmak gereksiz yere gizler. Neden normal kullanmıyorsunuz if...elsif? Bir vaka bildirimi ile bir koşulu karıştırmaya çalıştığınız anlaşılıyor. Neden? Koşullu zaman bloğunun içine koyun , örn. when 3; ( x < 2 ) ? 'apple' : 'orange'
sondra.kinsey

0

Birden fazla koşul için switch deyimi yazabiliriz.

Örneğin,

x = 22

CASE x
  WHEN 0..14 THEN puts "#{x} is less than 15"    
  WHEN 15 THEN puts "#{x} equals 15" 
  WHEN 15 THEN puts "#{x} equals 15" 
  WHEN 15..20 THEN puts "#{x} is greater than 15" 
  ELSE puts "Not in the range, value #{x} " 
END

1
Bu işe yaramaz; Yakut anahtar kelimeler (örn. case, when, end) Harf duyarlıdır ve bunun gibi büyük olamaz.
sondra.kinsey

NoMethodError (undefined method CASE 'için main: Object) `. @ Sondra.kinsey'in söylediği gibi, büyük harf kullanamazsınız. Ruby bunun bir SABİT olduğunu düşünecek.
Tin Man

0

caseİfadesi operatörü gibidir switchdiğer dillerde.

Bu switch...caseC'deki sözdizimidir :

switch (expression)
​{
    case constant1:
      // statements
      break;
    case constant2:
      // statements
      break;
    .
    .
    .
    default:
      // default statements
}

Bu case...whenRuby'nin sözdizimi :

case expression
  when constant1, constant2 #Each when statement can have multiple candidate values, separated by commas.
     # statements 
     next # is like continue in other languages
  when constant3
     # statements 
     exit # exit is like break in other languages
  .
  .
  .
  else
     # statements
end

Örneğin:

x = 10
case x
when 1,2,3
  puts "1, 2, or 3"
  exit
when 10
  puts "10" # it will stop here and execute that line
  exit # then it'll exit
else
  puts "Some other number"
end

Daha fazla bilgi için casebelgelere bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.