Ruby中如何在Game类访问Player类赋值的name变量
核心错误说明
你代码跑不通的本质是搞混了Ruby的变量作用域规则,同时类之间的传值逻辑写得不对:
- 你写的
@@name是类变量,仅在存在继承关系的类层级中共享,你的Player和Game是两个完全独立、无继承关联的类,两边定义的@@name根本不是同一个变量,自然读不到赋值结果。 - 你定义的
attr_accessor :name是针对实例变量@name生成读写方法,和你代码里用的@@name没有任何关系,等于这段accessor代码完全没生效。
正确实现方案
方案1:显式传值(最推荐,符合面向对象设计原则)
不要依赖隐式的跨类共享变量,Player实例拿到用户输入的名字后,显式赋值给Game实例的name属性即可,逻辑清晰无隐式依赖,不会出奇怪的作用域bug:
class Game attr_accessor :name def display_name puts "Name is #{@name}" end end class Player attr_accessor :name def get_name puts "What is your name? " @name = gets.chomp # 把输入存在当前Player实例的实例变量里 end end player = Player.new player.get_name game = Game.new game.name = player.name # 显式把player存储的名字传递给game实例 game.display_name
方案2:全局变量共享(极度不推荐,仅作原理说明)
如果非要实现一处赋值、所有类都能直接读的效果,可以用Ruby全局变量(变量名以$开头),但这种写法会让代码依赖关系混乱,后续维护很容易出难排查的bug,非极端场景不要用:
class Game def display_name puts "Name is #{$name}" end end class Player def get_name puts "What is your name? " $name = gets.chomp end end player = Player.new player.get_name game = Game.new game.display_name
补充规则说明
- Ruby变量作用域区分规则:
- 局部变量:小写/下划线开头,仅在当前代码块/方法内生效
- 实例变量:
@开头,属于单个类实例对象,不同实例之间互不干扰 - 类变量:
@@开头,仅在当前类的整个继承树内共享,无继承关系的类之间同名类变量完全独立 - 全局变量:
$开头,整个程序运行周期内全局生效
attr_accessor :属性名是语法糖,本质是自动生成对应实例变量的读、写两个方法,和类变量、全局变量无关,你之前的写法等于写了没用上的方法。
内容的提问来源于stack exchange,提问作者Oni
相关产品推荐
相关产品推荐

