Code Fix

中級

初期化前のインスタンス変数を参照すると警告なしで 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
出力: Balance:

@を付けずに代入するとローカル変数になり、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@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@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
出力: Count:

未初期化のインスタンス変数は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@total にします。

この問題を解いてみる →

よくある誤解

「初期化していないインスタンス変数を参照すればエラーになるはず」という思い込みは誤りです。Rubyのインスタンス変数は未初期化でもnilという値を持つ変数として静かに扱われ、後続の計算にnilが紛れ込みます。

まとめ

初期化前のインスタンス変数を参照すると警告なしで nil になるは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)