Ruby中类常量/类方法在其他类调用时返回nil的问题咨询
Ruby类常量与类方法变量nil问题分析及解决
原代码问题解释
第一个版本(类常量)
class Foo MAIN_COMPUTER = @computer_name attr_accessor :computer_name def initialize @computer_name = "IComputer" end end
MAIN_COMPUTER = @computer_name在类定义阶段执行,这里的@computer_name是类Foo自身的实例变量,而非Foo实例的变量。此时该变量未赋值,所以常量值为nil。initialize方法里的@computer_name是每个Foo实例创建时才会赋值的实例变量,和类本身的变量完全独立,因此创建Foo实例不会改变类常量的值。
第二个版本(类方法)
class Foo attr_accessor :computer_name def initialize @computer_name = "IComputer" end def self.main_computer @computer_name end end
- 类方法
self.main_computer中的@computer_name依然是类Foo自身的实例变量,和initialize里的实例变量不是同一个对象。类的这个变量从未被赋值,所以调用Foo.main_computer返回nil。
解决方案
根据需求,提供三种常见实现方式:
1. 固定常量值(适合值不变化的场景)
直接将常量设为固定字符串,实例变量复用该值:
class Foo MAIN_COMPUTER = "IComputer" attr_accessor :computer_name def initialize @computer_name = MAIN_COMPUTER end end class Gamer def opponent Foo::MAIN_COMPUTER end end me = Gamer.new p me.opponent # 输出 "IComputer"
2. 类级别的动态配置(适合需要全局修改值的场景)
用类实例变量存储值,搭配类方法读取/修改,实例初始化时同步类级别的值:
class Foo @main_computer = "IComputer" # 初始化类实例变量 attr_accessor :computer_name def initialize @computer_name = self.class.main_computer end def self.main_computer @main_computer end # 可选:添加修改类级别值的方法 def self.main_computer=(new_value) @main_computer = new_value end end class Gamer def opponent Foo.main_computer end end me = Gamer.new p me.opponent # 输出 "IComputer" # 修改类级别值后,新创建的实例会使用新值 Foo.main_computer = "GamingPC" new_foo = Foo.new p new_foo.computer_name # 输出 "GamingPC" p me.opponent # 输出 "GamingPC"
3. 关联特定实例的属性(需要基于某个实例的值)
用类变量保存目标实例的引用,类方法读取该实例的属性:
class Foo attr_accessor :computer_name @@main_instance = nil # 类变量存储主实例 def initialize @computer_name = "IComputer" @@main_instance = self # 初始化时将当前实例设为主实例 end def self.main_computer @@main_instance&.computer_name # 安全调用,避免实例未创建时报错 end end class Gamer def opponent Foo.main_computer end end # 必须先创建Foo实例,否则返回nil Foo.new me = Gamer.new p me.opponent # 输出 "IComputer"
内容的提问来源于stack exchange,提问作者Nnamdi
相关产品推荐
相关产品推荐

