Rubyでswitch文を書く方法


回答:


2670

Rubyは代わりにcaseを使用します

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 は、演算子を使用whenして、case句のオブジェクトを句のオブジェクトと比較します===。たとえば、1..5 === xではなくx === 1..5です。

これにより、when上記のように高度な句を使用できます。範囲、クラス、およびあらゆる種類のものを、単なる等価ではなくテストできます。

異なり、switch他の多くの言語でのステートメント、Rubyのはcase持っていないフォールスルーので、各終了する必要はありません、whenとはbreak。のwhenように、1つの句で複数の一致を指定することもできますwhen "foo", "bar"


12
渡された引数で正規表現を実行することもできます。次の行に/ thisisregex / と入力すると、「これは見つかった一致番号1#{$ 1}です」の終了
Automatico

8
また注目に値する、あなたは置くことによって、あなたのコードを短縮することができますwhenし、return同じ行にステートメントを:when "foo" then "bar"
アレクサンダー-復活モニカ

9
重要:とは異なり、switch他の多くの言語でのステートメントは、Rubyのcase持っていないフォールスルーので、各終了する必要はありません、whenとはbreak
janniks 2018

3
非常に多くの賛成票がまだキーワードに言及していませんthen。他の回答もご覧ください。
Clint Pachl

442

case...whenクラスを処理するときに、少し予期せず動作します。これは、===演算子を使用しているためです。

その演算子は、リテラルでは期待どおりに機能しますが、クラスでは機能しません。

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

つまりcase ... when、オブジェクトのクラスに対してaを実行する場合、これは機能しません。

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

「文字列または数値ではありません」と出力します。

幸い、これは簡単に解決できます。===オペレータは、それが返すように定義されているtrueあなたは、クラスでそれを使用し、第二オペランドとして、そのクラスのインスタンスを指定した場合:

Fixnum === 1 # => true

つまり、上記のコードは次のコードを削除することで修正できます.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

今日、答えを探しながらこの問題にぶつかりました。これが最初に表示されたページだったので、同じ状況にいる他の人に役立つと思いました。


obj = 'hello';ケースobj; 「こんにちは」が「それはこんにちは」の終わりを置くとき
Sugumar Venkatesan

持つ.classに参加して、おかげで注意することは興味深いです。もちろん、これは完全に適切な動作です(それがprintだと考えるのがよくある間違いであることがわかりましたがIt is a string)... オブジェクト自体ではなく、任意のオブジェクトのクラスをテストしています。したがって、たとえば、case 'hello'.class when String then "String!" when Class then "Class!" else "Something else" end結果は次のようになります。"Class!"これは、、などでも同じよう1.classに機能{}.classします。ドロップすると.class、これらのさまざまな値に対して"String!"または"Something else"が取得されます。
lindes

219

caseRubyで使っています。Wikipediaの「Switchステートメント」も参照してください。

引用:

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

もう一つの例:

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 のRubyプログラミング言語(第1版、O'Reilly)の約123ページでthenwhen節に続くキーワードは改行またはセミコロンで置き換えることができると書かれています(if then else構文のように)。(Ruby 1.8では、の代わりにコロンも使用できthenますが、この構文はRuby 1.9 では使用できなくなりました。)


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

ケーススイッチの結果に基づいて変数を定義しているため、これが私が使用した答えです。type = #{score}各行を言うのではなく、単にあなたがしたことをコピーできます。はるかにエレガントな私はまた、可能な場合はワンライナーがはるかに良い
onebree

これは答えの本質とは無関係ですが、4も完全な正方形です。
Nick Moore

109

ケース...いつ

チャックの答えにさらに例を追加するには:

パラメータあり:

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

パラメータなし:

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

kikitoが警告する「Rubyでswitch文を書く方法」に注意してください。


おかげで、これは1行に複数のオプションがある場合に役立ちました。私は使用しようとしていましたor
sixty4bit 2014

73

多くのプログラミング言語、特にCから派生したものは、いわゆるSwitch Fallthroughをサポートしています。私はRubyで同じことをするための最良の方法を探していて、それが他の人に役立つかもしれないと思いました:

Cのような言語では、フォールスルーは通常次のようになります。

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では、同じことを次の方法で実現できます。

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

これは厳密には同等ではありません。'a'コードブロックを実行する前に、'b'または'c'に進むことができないためですが、ほとんどの場合、同じように使用できるほど十分に似ています。


72

Ruby 2.0では、case次のようにステートメントでラムダを使用することもできます。

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

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

カスタムのStructを使用して、独自のコンパレータを簡単に作成することもできます ===

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

(「Ruby 2.0のケースステートメントでプロシージャを使用できますか?」からの例)

または、完全なクラスで:

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

(「RubyのCaseステートメントがどのように機能し、それを使って何ができるか」からの例。)


52

文字列のタイプの検索など、正規表現を使用できます。

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 はこれにcase等価オペランド===を使用します(@JimDevilleに感謝)。詳細については、「Rubyオペレーター」を参照してください。これは、@ mmdemirbasの例(パラメーターなし)を使用して行うこともできます。このアプローチのみが、これらのタイプのケースに適しています。



33

それは呼び出されcase、期待どおりに機能します。さらに===、テストを実装する多くの楽しい機能を提供しています。

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

楽しみにしてください:

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

また、任意のif / elseチェーン(つまり、テストに共通変数が含まれていない場合でも)をcase、初期caseパラメーターを省略して、最初の一致が必要な式を記述するだけで置き換えることもできることがわかりました。

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ステートメントの記述にを使用します。

caseドキュメントに従って:

Caseステートメントは、への引数の位置にあるオプションの条件caseと、0個以上のwhen句で構成されます。when条件に一致する最初の句(または、条件がnullの場合はブール値の真と評価される)が「優先」され、そのコードスタンザが実行されます。caseステートメントの値は、成功したwhen句の値かnil、そのような句がない場合です。

caseステートメントはelse句で終了できます。各whenステートメントは、カンマで区切られた複数の候補値を持つことができます。

例:

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

短いバージョン:

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

そして「Rubyのケースステートメント-高度なテクニック」がRubyを説明するようにcase;

範囲で使用できます

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

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

Regexで使用できます。

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

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

ProcsおよびLambdasで使用できます。

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

## => "lambdas"

また、独自のマッチクラスで使用できます:

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

場合によっては、メソッドのハッシュを使用することもできます。

whensの長いリストがあり、それらのそれぞれが(間隔ではなく)比較する具体的な値を持っている場合、メソッドのハッシュを宣言してから、そのようなハッシュから関連するメソッドを呼び出すほうが効果的です。

# 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

以来switch case、常に単一のオブジェクトを返す、我々は直接、その結果を印刷することができます。

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

20

多値の場合と無値の場合:

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

そして、ここでの正規表現ソリューション:

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
なぜだけcase some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end,はない(どこで改行を意味する)
tckmn 2014年

2
ああ、そして最初の部分はすでにこの回答でカバーされおり、多くの回答はすでに正規表現について言及しています。率直に言って、この答えは何も新しいものを追加しません、そして私はそれを削除するために反対投票と投票しています。
tckmn 2014年

@DoorknobofSnowこれは、正規表現ソリューションとスイッチケースでカンマ区切り値を使用できることを示しています。解決策があなたにそんなに痛みを与えている理由がわかりません。
123

彼らが合法的な等級である「F」を取得した場合、彼らの責任であなたのコードはケースを失っていますか?
Mike Graf、

私はこれのユーモアと、文字列をケースに一致させることができることを示しているという事実が好きです。
エメリー、

13

caseRubyでは2つの異なる方法で式を記述できます。

  1. 一連のifステートメントに似ています
  2. の横にターゲットを指定するcaseと、各when句がターゲットと比較されます。
age = 20
case 
when age >= 21
puts "display something"
when 1 == 0
puts "omg"
else
puts "default condition"
end

または:

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

あなたのコードは質問に答えるかもしれませんが、あなたのコードが何をするか、そしてそれが最初の問題をどのように解決するについて少なくとも短い説明を追加するべきです。
user1438038

このヒントについては、今後検討する予定です。
ysk

10

もっと自然な方法でこうすることができます

case expression
when condtion1
   function
when condition2
   function
else
   function
end

9

素晴らしい答えはたくさんありますが、1つのfactoidを追加したいと思いました。

Rubyの平等とオブジェクトの比較」は、このトピックに関する良い議論です。


7
参考までに、「space-ship」メソッドは<=>であり、比較がそれぞれ「より小さい」、「等しい」、「より大きい」、または「比較できない」を返すかどうかに応じて、-1、0、1、またはnilを返すために使用されます。RubyのComparableモジュールのドキュメントで説明しています。
ティンマン

7

上記の回答の多くで述べたように、===演算子はcase/ whenステートメントの内部で使用されます。

その演算子に関する追加情報を次に示します。

大文字と小文字の等価演算子: ===

Rubyの組み込みクラスの多く(String、Range、Regexpなど)は、===「case-equality」、「triple equals」、「threequals」とも呼ばれる独自の演算子の実装を提供します。クラスごとに実装が異なるため、呼び出されたオブジェクトのタイプによって動作が異なります。通常、右側のオブジェクトが左側のオブジェクトに「属している」または「のメンバーである」場合、trueを返します。たとえば、オブジェクトがクラス(またはそのサブクラスの1つ)のインスタンスであるかどうかをテストするために使用できます。

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

同じ結果は、次のような、おそらく最高の仕事に適している他の方法により達成することができますis_a?instance_of?

範囲の実装 ===

ときに===オペレータが範囲オブジェクトに対して呼び出され、右側の値は、左の範囲内にある場合、それは真を返します。

(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

===オペレーターは===左側のオブジェクトのメソッドを呼び出すことに注意してください。したがって、(1..4) === 3と同等(1..4).=== 3です。言い換えると、左側のオペランドのクラスは、===呼び出されるメソッドの実装を定義するため、オペランドの位置は交換できません。

正規表現の実装 ===

右側の文字列が左側の正規表現と一致する場合はtrueを返します。

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

上記の2つの例の唯一の関連する違いは、一致がある場合に===trueを=~返し、Rubyでは真の値である整数を返すことです。これはすぐに戻ります。


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
これが望ましいソリューションである理由と、それがどのように機能するかを説明すると、さらに役立ちます。コードを提供するだけでなく、教育したいと考えています。
ティンマン


1

私は使い始めました:

a = "secondcase"

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

puts var_name
>> "bar"

場合によってはコードの圧縮に役立ちます。


1
このようなコードは通常Hashcaseステートメントではなくを使用して実行する必要があります。
トム・ロード

そのスイッチが大きくなると、ハッシュを使用した方が速くなります。
Tin Man

1

ご使用の環境では正規表現はサポートされていませんか?例:Shopifyスクリプトエディター(2018年4月):

[エラー]:初期化されていない定数RegExp

ここここですでにカバーされている方法の組み合わせに続く回避策:

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

よりも優先順位が高い orため、クラスメソッドステートメントでs を使用しました。もしあなたがルビーナチなら、代わりにこれを使ったと想像してください。repl.itテスト。||.include?(item.include? 'A') || ...


1

,ではコンマ()を強調することが重要whenです。これ||は、ifステートメントのとして機能します。つまり、句の区切られた式間のAND比較ではなく、OR比較を実行します。次のcaseステートメントを参照してください。when

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

xは2以上ですが、戻り値は"apple"です。どうして?そのためx3および以来だっ',`` acts as an|| , it did not bother to evaluate the expressionx <2 '。

ANDを実行するには、以下のようにすることができますが、機能しません。

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

これは、理由は動作しません(3 && x > 2)Trueに評価し、そしてRubyは真の値を取り、それを比較xして===いるので、真されていない、x3です。

&&比較を行うにはcaseif/ elseブロックのように扱う必要があります。

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

Rubyプログラミング言語の本では、マッツは、この後者の形式は用の代替構文以外の何ものでもありません、単純な(そしてあまり使われない)形態であると言いますif/ elsif/ else。ただし、使用頻度が低いかどうかに関係なく&&、特定のwhen句に複数の式をアタッチする他の方法はありません。


これは私にとっては良いコーディングスタイルではないようです。まれな代替構文を使用すると、不必要に難読化されます。普通に使ってみませんif...elsifか?Caseステートメントと条件を混在させようとしているようです。どうして?whenブロックのに条件置くだけです。when 3; ( x < 2 ) ? 'apple' : 'orange'
sondra.kinsey

0

複数の条件のswitchステートメントを書くことができます。

例えば、

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
これは機能しません。Rubyのキーワードは、(例えばcasewhenend)大文字と小文字が区別され、次のように大文字にすることはできません。
sondra.kinsey

NoMethodError (undefined method CASE 'for main:Object) `。@ sondra.kinseyが言ったように、大文字は使用できません。Rubyはそれを定数だと考えます。
ティンマン

0

case声明演算子は似ているswitch他の言語インチ

これはswitch...caseC の構文です:

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

case...whenRuby の構文は次のとおりです。

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

例えば:

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

詳細については、 caseドキュメントを。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.