Ruby定义Struct时父类如何访问子类重写的VALID_COLORS常量
问题复现
原始问题代码如下:
class Parent VALID_COLORS = ["blue"] MyStruct = Struct.new(:color) do def initialize(color:) raise "invalid color" unless self.class::VALID_COLORS.include?(color) super(color: color) end end end class Subclass < Parent VALID_COLORS = ["red"] def call MyStruct.new(color: "red") end end
执行Subclass.new.call时抛出错误:
uninitialized constant Parent::MyStruct::VALID_COLORS
根因
Struct.new传入的代码块会在新生成的MyStruct类的作用域下执行,块内的self.class指向MyStruct本身,不是外层定义它的业务类,自然找不到定义在Parent/Subclass上的VALID_COLORS常量。
保留现有框架的修复方案
不需要调整现有常量定义、不需要给Struct新增业务入参、不需要修改call方法里的原有调用逻辑,只需要补两处轻量逻辑即可:
- 定义MyStruct时,捕获当前外层业务类的引用,作为MyStruct的宿主类
- 给父类加继承钩子,子类继承时自动生成属于子类自己的MyStruct子类,绑定子类作为宿主类,保证常量查找走子类作用域
修复后完整代码:
class Parent VALID_COLORS = ["blue"] MyStruct = Struct.new(:color) do # 定义Struct时,当前上下文self就是外层的Parent类,直接存为宿主类 @host_class = self class << self attr_accessor :host_class end def initialize(color:) raise "invalid color" unless self.class.host_class::VALID_COLORS.include?(color) super(color: color) end end # 子类继承父类时自动触发 def self.inherited(subclass) # 给子类创建专属的MyStruct子类,绑定子类为宿主类 subclass.const_set(:MyStruct, Class.new(self::MyStruct) do self.host_class = subclass end) end end class Subclass < Parent VALID_COLORS = ["red"] def call # 原有调用逻辑完全不需要改动 MyStruct.new(color: "red") end end
效果验证
- 执行
Subclass.new.call:正常返回#<struct Subclass::MyStruct color="red">,传入"blue"会正确抛出invalid color错误 - 执行
Parent::MyStruct.new(color: "blue"):正常通过校验,传入"red"会抛错
完全符合预期的常量重写、校验逻辑。
内容的提问来源于stack exchange,提问作者runguacrun
相关产品推荐
相关产品推荐

