こんにちは、かつコーチです。
Rubyを書いていると、必ずと言っていいほど出会うのがnil関連のエラーです。
私も実務でAPIのレスポンスを扱っていたとき、想定外のnilに何度も足元をすくわれました。
この記事では、nilとは何かという基本から、nil?メソッドやぼっち演算子を使った安全な書き方までを解説します。
基本の書き方・nilの正しい扱い方
nilとは「何もない」ことを表す値
nilとは、Rubyにおいて「値が存在しない」ことを表す特別なオブジェクトです。
他の言語のnullやNoneに近い存在ですが、Rubyではnil自体もNilClassというクラスのオブジェクトです。
p nil.class
# => NilClass
変数の初期化前や、ハッシュに存在しないキーを参照したときなどに、nilが返ってきます。
user = { name: "Sato" }
p user[:age]
# => nil
nil?メソッドで存在チェックをする
nil?メソッドとは、そのオブジェクトがnilかどうかを真偽値で返すメソッドです。
value = nil
p value.nil?
# => true
value = "Ruby"
p value.nil?
# => false
if文と組み合わせれば、nilだった場合の分岐処理を安全に書けます。
def greet(name)
if name.nil?
puts "名前が指定されていません"
else
puts "Hello, #{name}"
end
end
greet(nil)
# => 名前が指定されていません
ぼっち演算子(&.)でnilガードする
ぼっち演算子(&.)とは、レシーバーがnilのときにメソッド呼び出しをスキップしてnilを返す演算子です。
見た目が体育座りをしている人に似ていることから、この呼び名がついています。
user = nil
p user&.name
# => nil
通常の.で呼び出すとエラーになる場面でも、&.を使えばエラーにならずnilが返ります。
users = [{ name: "Sato" }, nil, { name: "Suzuki" }]
users.each do |user|
puts user&.[](:name) || "不明なユーザー"
end
# => Sato
# => 不明なユーザー
# => Suzuki
よくあるつまずきポイント・エラー対処
NoMethodError for nil:NilClassへの対処
NoMethodError for nil:NilClassとは、nilに対して存在しないメソッドを呼び出したときに出るエラーです。
❌ Before
def fetch_user_name(users, id)
user = users.find { |u| u[:id] == id }
user[:name].upcase
end
users = [{ id: 1, name: "Sato" }]
puts fetch_user_name(users, 2)
undefined method '[]' for nil (NoMethodError)
実際に私がAPI連携の実装で経験したのが、まさにこのパターンです。
findで条件に合うデータが見つからないとnilが返ってくるのに、その後すぐに[:name]でアクセスしてしまい、本番環境でエラーが発生しました。
✅ After
def fetch_user_name(users, id)
user = users.find { |u| u[:id] == id }
user&.[](:name)&.upcase || "ユーザーが見つかりません"
end
users = [{ id: 1, name: "Sato" }]
puts fetch_user_name(users, 2)
# => ユーザーが見つかりません
findやdetectのように「見つからなければnilを返す」メソッドの後には、必ずnilチェックを入れる習慣をつけましょう。
配列の空チェックとnilチェックの混同
配列が「空である」ことと「nilである」ことを混同してしまうのも、よくあるつまずきです。
❌ Before
def show_items(items)
if items.nil?
puts "アイテムがありません"
end
items.each { |item| puts item }
end
show_items([])
(何も表示されないが、なぜ表示されないのか分かりにくい)
itemsがnilではなく空配列[]だった場合、nil?のチェックをすり抜けてしまい、eachが0回実行されて終わります。
エラーにはなりませんが、意図した「アイテムがありません」の表示がされず、原因調査に時間がかかりました。
✅ After
def show_items(items)
if items.nil? || items.empty?
puts "アイテムがありません"
return
end
items.each { |item| puts item }
end
show_items([])
# => アイテムがありません
nilか空かの両方を考慮したいときは、nil?とempty?をセットで使うか、Array()でnilを空配列に変換してから処理すると安全です。
まとめ
この記事のポイント
- nilはRubyで「値が存在しない」ことを表す
NilClassのオブジェクトである - nil?メソッドを使えば、
nilかどうかを安全に判定できる - ぼっち演算子(&.)を使うと、
nilに対するメソッド呼び出しでもエラーにならない findなど「見つからなければnilを返す」メソッドの後は、必ずnilチェックを入れるnilと空配列は別物なので、両方を考慮した条件分岐が必要になる場合がある
次に読むべき記事
nilの扱い方に慣れたら、次はプロジェクトの土台となるライブラリ管理を学びましょう。
「Gemfileとbundlerの基本:パッケージ管理を理解する」で、gemの仕組みとbundle installの挙動を解説しています。