Ruby OOP中Game类调用player_name触发NameError的原因排查
问题原因分析
你遇到的undefined local variable or method 'player' for Game:Class错误,核心问题是类方法和实例变量的访问权限不匹配:
player_name和computer_name是用self.定义的类方法,这类方法属于Game这个类本身,不绑定任何具体的游戏实例。@player和@computer是在initialize方法中赋值的实例变量,它们只属于某个具体的Game对象,类方法无法直接访问这些实例变量。
当你调用Game.player_name时,Ruby找不到和类绑定的player变量,因此报错。
两种解决方案
方案一:单游戏实例场景(全局唯一游戏)
如果你的井字棋程序只需要同时运行一个游戏,可以在Game类中保存当前实例的类变量,让类方法通过这个类变量访问实例数据:
class Game attr_accessor :player, :computer @@board = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] @@current_game = nil # 类变量保存当前游戏实例 def initialize(player, computer) @player = player @computer = computer @@current_game = self # 初始化时绑定当前实例 puts "#{player.name} vs #{computer.name}" end def self.player_name puts "#{@@current_game.player.name}" end def self.computer_name puts "#{@@current_game.computer.name}" end def self.status puts "#{@@board}" end end
执行代码无需修改,Game.player_name就能正常输出玩家名字。
方案二:多游戏实例场景(支持多个游戏同时运行)
如果需要同时运行多个游戏实例,应该把player_name和computer_name改成实例方法(去掉self.),通过具体的Game实例调用:
修改后的Game类:
class Game attr_accessor :player, :computer @@board = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] def initialize(player, computer) @player = player @computer = computer puts "#{player.name} vs #{computer.name}" end # 去掉self.,转为实例方法 def player_name puts "#{@player.name}" end def computer_name puts "#{@computer.name}" end def self.status puts "#{@@board}" end end
修改后的执行代码:
p1 = Player.new('John') p2 = Player.new('Computer') game = Game.new(p1, p2) # 保存游戏实例 game.player_name # 通过实例调用方法 game.computer_name
关键知识点补充
- 实例方法:不带
self.,只能通过具体的类实例(比如game = Game.new(...)后的game)调用,能访问该实例的所有实例变量(@player、@computer等)。 - 类方法:带
self.,通过类本身调用(比如Game.player_name),只能访问类变量(@@board、@@current_game等),不能直接访问实例变量。
内容的提问来源于stack exchange,提问作者Ong K.S
相关产品推荐
相关产品推荐

