※ 本記事の内容は作者のブログにも書いているのでこちらも応援お願いします🙇♂️
はじめに
以下のようなclassを考えます
class Person
attr_accessor :first_name, :last_name
def full_name
last_name + first_name
end
end
このクラスは、苗字と名前を与えると、full_name関数でそれを合わせた形で取り出すことができます
person = Person.new
person.last_name = '山田'
person.first_name = '太郎'
puts person.full_name # 山田太郎
では、以下の場合はどうでしょうか
person = Person.new
puts person.full_name
実行すると以下のようなエラーが出てしまいました
`full_name': undefined method `+' for nil:NilClass (NoMethodError)
last_name + first_name
nil safeについて
一般的にプログラミング言語には、何も入っていないことを表すnull (Rubyの場合はnil)という概念があります
変数の中にnullが入ることを考慮せずに処理を書いた場合、意図しないエラーを起こすことがあります (一般的にヌルポと言われるものもこの一部です)
上の例の場合、last_name (およびfirst_name) にnilが入ってしまっているため、エラーが出てしまっているわけです
逆にnullが入ることを考慮し、nullが入っても動く仕組みにすることを null safe (Rubyの場合はnil safe)と言います
rubyにおけるnil safe4パターン
では、上記でエラーを回避するための仕組みを考えてみましょう
[パターン1] begin rescue
エラーが出る前提の元、エラーが出た場合の処理も記述する、と言う方法です
def full_name
begin
last_name + first_name
rescue
''
end
end
エラーは出ない反面、begin rescue間のエラーを握り潰してしまう(どんなエラーが出たかを考慮しない)という意味ではかなり雑な対処法と言えます。
[パターン2] nil判定
1つ1つの変数でnilかどうかを判定してあげるパターンです
def full_name
(last_name || '') + (first_name || '')
end
これはシンプルにかけて良さそうですね
ただし、rubyはfalseとnil以外を全て真値として判断してしまうため(本筋とは外れますが)こんな意地悪なことをされてしまうとエラーになります
person = Person.new
person.last_name = true
person.first_name = '太郎'
puts person.full_name
[実行結果]
`full_name': undefined method `+' for true:TrueClass (NoMethodError)
(last_name || '') + (first_name || '')
^
動的型付言語の宿命ではありますが、この場合は(想像している以外の値を入れられているため)エラーを出すのが正しいのかもしれません
[パターン3] to_s method
rubyにおいてnilはclassです
その特性を上手く活かすとこういう回避の仕方もできます
def full_name
last_name.to_s + first_name.to_s #nil.to_sは空文字を返す
end
これはnil classが to_s(文字列変換)のメソッドを持っているためです
ちなみに先ほどの意地悪な例はこのパターンだとエラーを出さずに通りますが、これは良い場合と悪い場合がありそうです
person = Person.new
person.last_name = true
person.first_name = '太郎'
puts person.full_name # true太郎
[パターン4] safe navigation operator
いわゆる「 ぽっち演算子 」 と呼ばれる方法です
def full_name
last_name&.+ first_name
end
この&.は 左側にある変数がnilの場合には処理を実行せずにnilを返す というものです
(したがってfull_nameはlast_nameがnilの場合はnilを返します)
ただし、逆に言えば以下のような場合は結局再度nil safeを考慮しないといけなくなるため、問題を先送りにしているだけとも言えます
person = Person.new
puts person.full_name + 'さん' # full_nameがnilを返すためここでエラーになる
まとめ
- rubyのnil safeには様々な方法がある
- どれも一長一短なので、場合によって使い分けることが重要
上手く使い分けて安全性の高いプログラムを作れるようになりたいものです