Rubyのifで=を使った時に警告がでるときでないとき
Effective Rubyに
この例のようにif式の条件部で代入 することは一般的である。逆に言えば、本当は"=="を使うべきところでうっかり"="を使ってしまうこともある。この種のミスには気をつけたい
と書かれていて、あれ、ifで=を使ったら警告でなかったっけ?*1 と思って調べてみた。
#!/usr/bin/env ruby -W -v a = 0 if a = 1 end b1 = 1 b2 = 1 if b1 = b2 end if $c = 1 end d = 0 if d = 'hoge'.match(/hoge/) end e = 0 if e = 'hoge'.upcase end class Hoge attr_accessor :f def g if @g1 = 1 end end end hoge = Hoge.new if hoge.f = 1 end hoge.g h = nil puts h = false ? 1 : h.class.to_s
このようなコードを実行してみる。最後の例は、下記のコメントで指摘されていたので入れてみた。
if式 / if文 の条件節で、左辺に定数を書くべき言語はあるか? @ajiyoshi.gist
実行結果は下記の通りである。
ruby 2.1.4p265 (2014-10-27 revision 48166) [x86_64-darwin14.0] ./hoge.rb:4: warning: found = in conditional, should be == ./hoge.rb:12: warning: found = in conditional, should be == ./hoge.rb:27: warning: found = in conditional, should be == NilClass
この通り、下記の場合しか警告がでない。
if x = 1 end if $c = 1 end def g if @g1 = 1 end end
条件演算子の例については、見ての通りで、演算子の評価順の問題である。y = false
が先に評価されるのであれば、FalseClassと出力されるはずだが、そうなっていない。というか、val = bool ? a : b
という代入はCなどではよく使われるので、考慮不足な指摘な感じが否めない。
まとめ
警告がでるのは下記の場合に限られる(ようだ)。
- 左辺が変数であり、右辺が1や'hoge'のような即値の時の代入
ゆえに、下記のような場合は警告がでない。
- 右辺が即値でない場合
- 代入メソッドの呼び出しの場合
右辺が即値の場合、絶対に実行されるか、絶対に実行されないのいずれかになるため、ミスの可能性が極めて高いといえる。ゆえに警告がでるのは妥当だろう。
ところが、代入メソッドの場合、右辺が即値でも警告はでない。代入メソッドの戻り値によるからかと思ったが、代入メソッドは引数で指定された値を返すという挙動をする。つまり、puts o.v = 1
とした場合、o#v=(v)
で何を返していても1が出力される。なので、代入メソッドの場合も警告がでる方が妥当だと思うのだがなぜかでない。よく分からない挙動である。
- 作者: Peter J. Jones,arton,長尾高弘
- 出版社/メーカー: 翔泳社
- 発売日: 2015/01/09
- メディア: 大型本
- この商品を含むブログ (6件) を見る