web-dev-qa-db-ja.com

Rubyでswitchステートメントを書く方法

Rubyでswitch文を書くにはどうすればいいですか?

1937
Readonly

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のcasefall-through を持たないので、それぞれのwhenbreakで終わらせる必要はありません。 when "foo", "bar"のように、1つのwhen句に複数の一致を指定することもできます。

2484
Chuck

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

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

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

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

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')
end

「それは文字列ではありません」と表示します。

幸い、これは簡単に解決できます。 ===演算子は、クラスとともに使用し、そのクラスのインスタンスを2番目のオペランドとして指定した場合に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')
end

私は答えを探している間今日この問題にぶつかりました、そして、これは最初に現れるページでした、それで私はそれが私の同じ状況で他の人に役に立つだろうと考えました。

418
kikito

Rubyでは case によって行われます。 Wikipediaに関するこの記事 も参照してください。

引用:

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

The Ruby Programming Lanugage (第1版、O'Reilly)の123ページ周辺(私はKindleを使用しています)では、then句に続くwhenキーワードを改行またはセミコロンで置き換えることができます(ちょうど同じ) if then else構文にあります。 (Ruby 1.8ではthen..の代わりにコロンを使用することもできます。しかし、この構文はRuby 1.9では使用できなくなりました。)

199

case ... when

Chuck's answer に例を追加するには:

パラメータ付き:

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

問題 - キキトが警告していることに注意してください。

91
mmdemirbas

多くのプログラミング言語、特に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'にコードブロックを実行させることは不可能であるため、これは厳密には同等ではありませんが、大部分は同じように有用であると十分に似ています。

69
Robert Kajic

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ではcaseステートメントでprocを使うことができますか? "からの例です。)

あるいは、完全なクラスでは:

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ステートメントのしくみとあなたができること "からの例)

65
James Lim

文字列の種類を見つけるなどの正規表現を使用できます。

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 Operators "にあります。これは@mmdemirbasの例を使用して(パラメータなしで)実行することもできますが、このような場合にはこのアプローチのみがよりクリーンです。

50
Haris Krajina

RubyのスイッチケースでOR条件を使用する方法を知りたければ、

したがって、caseステートメントでは、,ifステートメントの||と同等です。

case car
   when 'Maruti', 'Hyundai'
      # Code here
end

Rubyのcase文でできることは他にもたくさんある

30

これは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

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

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

あなたのケースに応じて、あなたはメソッドのハッシュを使うことを好むかもしれません。

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

# 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])
20
Alexander

複数値の場合と値なしの場合

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
19
123

switch caseは常に単一のオブジェクトを返すので、その結果を直接出力することができます。

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

Rubyはswitch文を書くためにcaseを使います。

Ruby Docs に従って:

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

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

例:

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

そしてこのブログのように Honeybadger はRuby Caseについて説明します。

範囲 と共に使用できます。

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

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

正規表現 と共に使用できます。

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
19
Lahiru

Rubyでは2つの異なる方法でcase式を書くことができます。

  1. 一連の "if"文に似ています
  2. ケースの横にターゲットを指定し、各 "when"節をターゲットと比較します。

第一道

age = 20
case 
when age >= 21
puts "display something"
when 1 == 0
puts "omg"
else
puts "default condition"
end

2番目の方法

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

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

case expression
when condtion1
   function
when condition2
   function
else
   function
end
8
Navin

たくさんの素晴らしい答えがありますが、私は1つのファクトイドを追加したいと思いました。

これはトピックについてのよい議論です http://www.skorks.com/2009/09/Ruby-equality-and-object-comparison/ /

8
jmansurf
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
5
Prabhakar

上記の回答の多くで述べられているように、===演算子はcase/whenステートメントの裏で使われています。

これはその演算子に関するいくつかの追加情報です。

ケース等価演算子:===

String、Range、RegexpなどのRubyの組み込みクラスの多くは、独自の===演算子の実装を提供します。これらは、大文字小文字の区別、三重等号または三重等号とも呼ばれます。各クラスで実装が異なるため、呼び出されたオブジェクトの種類によって動作が異なります。一般に、右側のオブジェクトが左側のオブジェクトの「に属している」または「のメンバー」である場合は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?。

===の範囲実装

範囲オブジェクトに対して===演算子が呼び出されると、右側の値が左側の範囲内にある場合にtrueが返されます。

(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/=== "今日のzazenの練習"#出力:=> true#は "今日のzazenの練習"に似ています=〜/ zen /

上記2つの例の唯一の関連する違いは、一致があるとき===がtrueを返し、=〜が整数を返すということです。これはRubyでは真の値です。まもなくこれに戻ります。

5
BrunoFacca
$age =  5
case $age
when 0 .. 2
   puts "baby"
when 3 .. 6
   puts "little child"
when 7 .. 12
   puts "child"
when 13 .. 18
   puts "youth"
else
   puts "adult"
end

reference => https://www.tutorialspoint.com/Ruby/ruby_if_else.htm

4
Navneet

複数の条件に対して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
2
Foram Thakral

私は使い始めました:

a = "secondcase"

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

puts var_name
>> "bar"

場合によってはコードをコンパクトにするのに役立ちます。

1
deepfritz

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

[エラー]:未初期化定数 RegExp

here および here で既に説明した方法の組み合わせによる回避策。

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

||.include?よりも優先順位が高いので、クラスメソッドステートメントでorsを使用しました。あなたが Ruby-nazi であるなら、私が代わりにこの(item.include? 'A') || ...を使ったと想像してください。 repl.it test。

1
CPHPython

When句でカンマ「、」を強調することは重要です。|| if文の場合、つまり、when句の区切られた式の間ではAND比較ではなく、OR比較を行います。以下のcase文をチェックしてください。明らかに、xは2以上ですが、戻り値は 'Apple'です。どうして? xは3であり、 '、'は||として機能するので、式 'x <2'を評価するのに面倒ではありませんでした。

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

あなたは、ANDを実行するために、以下のようなことができると思うかもしれません。しかし、うまくいきません。これは、(3 && x> 2)がtrueと評価され、RubyがTrueの値を取り、それを===でxと比較するためです。xは3なので、これは明らかに正しくありません。

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

&&比較を行うには、case likeを扱い、if elseでブロックする必要があります。

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

Rubyプログラミング言語の本の中で、Matzはこの後者の形式は単純な(そしてまれにしか使われない)形式であると言っています。これはif/elsif/elseの代替構文にすぎません。しかし、使用頻度が低いかどうかにかかわらず、特定の 'when'句に複数の&&式を付加する他の方法はありません。

0
Donato