Rubyのnilガードとは

ユーザーからの入力などで、名前や電話番号などが入っていた場合があるとする。
これらをたとえばDBに入れようとしても、nilだとエラーになってしまうかもしれない。

そんなときに、nilを防ぐための書き方がある。
これをnilガードという。

実際に例を見てみよう。

class Person
attr_accessor :last, :first
def fullname
@last ||= ""
puts "#{@last.upcase},#{@first}"
end
end
takashi = Person.new
takashi.first = "takashi"
takashi.last = "sato"
#=>「SATO,takashi」と表示される
takashi.fullname
takeshi = Person.new
takeshi.first = "世紀末リーダたけし"
#=>「,世紀末リーダたけし」と表示される
takeshi.fullname

この例では、

@last ||= ""

の部分で、nilガードを行っている。

@lastはnilなんだけど、upcaseを実行しても参照エラーにならない。
それは、ちゃんと@lastに””という空の文字列が入れられていたからだ。

この構文はちょっとわかりづらいけれど、

@last || (a = "")

と同じ意味だ。

その証拠に、fullnameメソッドを

def fullname
@last || @last = ""
puts "#{@last.upcase},#{@first}"
end

と変えても全く同じ結果になる。

「||」演算子は、被演算子のいずれかがtrueであれば、trueを返す。
そして、nilとfalse以外は全てtrueになるのが||演算子の特徴でもある。

つまり、最初の@lastの部分で、@lastがnilであるかどうか判定している。
そいで、nilであった場合は、1番目の判定(左側の判定)でfalseになって、
2番目の判定(右側)を行う。

そこで、@lastに””(空文字)を代入するという処理を行っている。

if文にするとこうなる。

  def fullname
if @last != nil
@last = @last
else
@last = ""
end
puts "#{@last.upcase},#{@first}"
end

上のif文は、nilブロック構文と同じ意味だ。

最後に、2番目の演算をfalseにすると・・・

def fullname
@last ||= false
puts "#{@last.upcase},#{@first}"
end

upcaseでエラーが発生する。

tmp2.rb:8:in `fullname': undefined method `upcase' for false:FalseClass (NoMeth
dError)
from tmp2.rb:24:in `<main>'

メタプログラミングRuby

メタプログラミングRuby

メタプログラミング Rubyの付録、p.268に書いてあった。
こういうtipsは「知ってるか知らないか」で違いが出る部分なので、しっかり押さえておきたいと思った。
本を読むまで知らなかったもん。