16
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rubyトリビア】elsif の条件式は省略可能!?

Posted at

Rubyのif文ではelsifを使って複数の条件を書くことができます。

def greet_to(name)
  if name == 'Alice'
    puts 'Hi, Alice!'
  elsif name == 'Bob'
    puts 'Hi, Bob!'
  end
end

greet_to('Alice')
#=> Hi, Alice!

greet_to('Bob')
#=> Hi, Bob!

それでは次のようにelsifの条件式を無くすとどうなるでしょうか?

 def greet_to(name)
   if name == 'Alice'
     puts 'Hi, Alice!'
-  elsif name == 'Bob'
+  elsif
     puts 'Hi, Bob!'
   end
 end

答えはこうです。(あれ、さっきと同じ!?)

greet_to('Alice')
#=> Hi, Alice!

greet_to('Bob')
#=> Hi, Bob!

条件式なしのelsifはelsif trueと同じ意味になるんでしょうか?🤔
ためしに今度はifの条件式もなくしてみましょう。

 def greet_to(name)
-  if name == 'Alice'
+  if
     puts 'Hi, Alice!'
   elsif
     puts 'Hi, Bob!'
   end
 end

これだと結果はどうなるんでしょうか?というか、そもそもこんなコード、動くんでしょうか?

greet_to('Alice')
#=> Hi, Alice!
#   Hi, Bob!

greet_to('Bob')
#=> Hi, Alice!
#   Hi, Bob!

動いた〜!けど、なんだこれ?AliceもBobも両方出力されてますね……。

種明かし

実はこれ、こう書いたのと同じ意味になっています。

def greet_to(name)
  if puts 'Hi, Alice!'
    # Do nothing
  elsif puts 'Hi, Bob!'
    # Do nothing
  end
end

つまり、putsの呼び出しが条件式として扱われているわけですね。
で、putsの戻り値はnilなのでputs 'Hi, Alice!'は偽として扱われ、続いてelsifの条件式 puts 'Hi, Bob!' が実行される、というわけです。

なので、たとえばputsの代わりにpメソッドを使うと結果が変わります。(pメソッド戻り値は引数として渡したオブジェクト自身になり、真と評価されるため)

def greet_to(name)
  if
    p 'Hi, Alice!'
  elsif
    p 'Hi, Bob!'
  end
end

greet_to('Alice')
#=> "Hi, Alice!"

greet_to('Bob')
#=> "Hi, Alice!"

最初に見せたコードも条件式をわざと改行させるとこんなふうに書けます。(よい子はマネしちゃいけません)

def greet_to(name)
  if
    name == 'Alice'
    puts 'Hi, Alice!'
  elsif
    name == 'Bob'
    puts 'Hi, Bob!'
  end
end

greet_to('Alice')
#=> Hi, Alice!

greet_to('Bob')
#=> Hi, Bob!

こんなコードをわざわざ書く人はいないでしょうし、書くべきでもないですが、if/elseと書くつもりがうっかりif/elsifと書いてしまうと、構文エラーにならない代わりに予期しない不具合を起こすかもしれないので気をつけましょう。

def greet_to(name)
  if name == 'Alice'
    puts 'Hi, Alice!'
  elsif # ← 本当はelseと書くつもりが間違えた
    puts 'Hi, Bob!'
  end
end

なお、ifやelsifのうしろには条件式が必要なので、次のようなコードを書いたときは構文エラーになります。

def greet_to(name)
  if name == 'Alice'
    puts 'Hi, Alice!'
  elsif
    # elsifに対応する条件式がない(構文エラー)
  end
end
#=> syntax error, unexpected `end'
#   syntax error, unexpected end-of-input, expecting `end'

おまけ:case/whenだったら?

以下のようにcase/whenを使った条件分岐で、when 'Bob'whenだけにしてみるとどうなるでしょうか?

def greet_to(name)
  case name
  when 'Alice'
    puts 'Hi, Alice!'
  when
    puts 'Hi, Bob!'
  end
end
#=> syntax error, unexpected string literal, expecting `do' or '{' or '('
#   puts 'Hi, Bob!'

むむむ、構文エラーが起きました。
が、次のように()付きでputsを呼び出すとエラーになりません。

def greet_to(name)
  case name
  when 'Alice'
    puts 'Hi, Alice!'
  when
    puts('Hi, Bob!')
  end
end

greet_to('Alice')
#=> Hi, Alice!

greet_to('Bob')
#=> Hi, Bob!

とはいえ、これもif/elsifの場合と同じく、puts('Hi, Bob!')がwhen節の条件式になっているだけです。

def greet_to(name)
  case name
  when 'Alice'
    puts 'Hi, Alice!'
  when puts('Hi, Bob!')
    # (こう書いてるのと同じ)
  end
end
16
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?