初期化前のインスタンス変数を参照すると警告なしで nil になる
initializeで値を設定し忘れたインスタンス変数は、エラーにも警告にもならず単にnilとして扱われます。存在しないローカル変数がNameErrorになるのとは対照的です。
なぜエラーが出ないのか
出力: Balance:
(エラーなし)- Rubyは何も報告しません。文法として正しいためです
出力: Balance:- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 class Account 2 def initialize(balance) 3 balance = balance ^ 4 end 5 6 def show 7 puts "Balance: #{@balance}" 8 end 9 end 10 11 Account.new(500).show
@を付けずに代入するとローカル変数になり、initializeを抜けた時点で消えます。@balanceは初期化されないままnilで残ります。
直し方: balance を @balance にします。
パターン2
1 class Player 2 def initialize(score) 3 score = score ^ 4 end 5 6 def show 7 puts "Score: #{@score}" 8 end 9 end 10 11 Player.new(80).show
エラーにも警告にもならないため、出力を確認するまで初期化し忘れに気づけません。
直し方: score を @score にします。
パターン3
1 class Character 2 def initialize(level) 3 level = level ^ 4 end 5 6 def show 7 puts "Level: #{@level}" 8 end 9 end 10 11 Character.new(5).show
インスタンス変数のつもりで書いたローカル変数は、メソッドを抜けると同時に消えてしまいます。
直し方: level を @level にします。
パターン4
1 class Cart 2 def initialize(count) 3 count = count ^ 4 end 5 6 def show 7 puts "Count: #{@count}" 8 end 9 end 10 11 Cart.new(3).show
未初期化のインスタンス変数はNameErrorにならず、静かにnilとして扱われます。
直し方: count を @count にします。
パターン5
1 class Order 2 def initialize(total) 3 total = total ^ 4 end 5 6 def show 7 puts "Total: #{@total}" 8 end 9 end 10 11 Order.new(999).show
@の付け忘れは見た目がよく似ているため、コードを読むだけでは見落としやすいミスです。
直し方: total を @total にします。
よくある誤解
「初期化していないインスタンス変数を参照すればエラーになるはず」という思い込みは誤りです。Rubyのインスタンス変数は未初期化でもnilという値を持つ変数として静かに扱われ、後続の計算にnilが紛れ込みます。
実務での勘所
ローカル変数と違いインスタンス変数が警告なしでnilになるのは、Rubyがそのオブジェクトにどんなインスタンス変数が存在しうるかを事前に把握できないためです。ローカル変数はそのメソッドの中のコードを読めば、代入されている変数の一覧をあらかじめ確定できます。インスタンス変数はinitializeの外からでも実行時に動的にいつでも代入できてしまうため、「このオブジェクトが最終的に持つインスタンス変数の一覧」をコードを読んだだけで確定する方法がありません。確定できない以上、Rubyは未初期化かどうかを判定する手立てを持たず、単にnilとして扱うしかないのです。