如何在Ruby Struct子类中定义类实例变量及实例方法共享变量
在Ruby Struct子类中定义内部共享的类实例变量的正确方式
错误原因分析
你遇到的NameError是因为在Struct.new的定义块执行时,Triple常量还未完成赋值——Struct.new的返回值才会被绑定到Triple,所以此时直接引用Triple会触发常量未初始化的错误。
解决方案一:通过类方法封装类实例变量
利用定义块内self指向当前Struct类的特性,用self.new创建实例,再定义类方法封装类实例变量的访问,让实例方法可以安全调用:
Triple = Struct.new(:x, :y, :z) do # 类上下文里self就是Triple类,用self.new避免引用未初始化的常量 @tmp = self.new(0.0, 0.0, 0.0) # 定义类方法获取类实例变量(可设为私有进一步限制外部访问) def self.tmp @tmp end def mul(s) # 通过类方法访问共享的类实例变量 shared_tmp = self.class.tmp shared_tmp.x = x * s shared_tmp.y = y * s shared_tmp.z = z * s shared_tmp end end one = Triple[1.0, 1.0, 1.0] puts Triple.tmp puts one one.mul(7.5) puts Triple.tmp puts one
解决方案二:直接通过instance_variable_get访问
如果不需要额外封装类方法,也可以直接在实例方法中通过self.class.instance_variable_get获取类实例变量:
Triple = Struct.new(:x, :y, :z) do @tmp = self.new(0.0, 0.0, 0.0) def mul(s) shared_tmp = self.class.instance_variable_get(:@tmp) shared_tmp.x = x * s shared_tmp.y = y * s shared_tmp.z = z * s shared_tmp end end one = Triple[1.0, 1.0, 1.0] puts Triple.instance_variable_get(:@tmp) puts one one.mul(7.5) puts Triple.instance_variable_get(:@tmp) puts one
执行结果
两种方案的输出都和你原来的全局变量版本一致:
#<struct Triple x=0.0, y=0.0, z=0.0> #<struct Triple x=1.0, y=1.0, z=1.0> #<struct Triple x=7.5, y=7.5, z=7.5> #<struct Triple x=1.0, y=1.0, z=1.0>
访问控制说明
如果要彻底禁止外部访问@tmp,可以把类方法设为私有:
private_class_method :tmp
这样外部无法通过Triple.tmp访问,但实例方法内部仍可正常调用self.class.tmp。
内容的提问来源于stack exchange,提问作者igouy
相关产品推荐
相关产品推荐

