从Struct子类化使用attr_accessible进行子类化

时间:2012-05-25 17:49:59

标签: ruby

在Ruby 1.8.6中,我可以编写class PerformableMethod < Struct.new(:object, :method, :args)

现在在Ruby 1.9.3中,会抛出错误:superclass mismatch for class PerformableMethod

如果我将代码更改为:

,则有效
class PerformableMethod
    attr_accessor :object, :method_name, :args

但为什么结构不起作用?

2 个答案:

答案 0 :(得分:5)

类名在1.9和2.0中也是可选的。问题是:

> Struct.new(:asdf, :qwer) == Struct.new(:asdf, :qwer)
 => false 

即使您为Struct提供了班级名称:

> Struct.new("Zxcv", :asdf, :qwer) == Struct.new("Zxcv", :asdf, :qwer)
(irb):22: warning: redefining constant Struct::Zxcv
 => false 

这意味着如果您在加载或需要的文件中有此内容:

class MyClass < Struct.new(:qwer, :asdf)
  def some_method
    puts "blah"
  end
end

...然后,如果你再次加载它 - 也许是因为你改变了一些东西而你想在没有重新启动irb的情况下尝试它,或者你可能在开发模式下运行Rails并且它在每个请求上重新加载类 - 然后你得到例外:

TypeError: superclass mismatch for class MyClass

...因为每次您的课程定义运行时,它都会宣布一个全新的Struct作为MyClass的超类。向Struct.new()提供类名无济于事,如第二个代码块所示;这只是添加了一个关于重新定义常量的警告,然后无论如何都打开了类。

避免异常的唯一方法是将Struct存放在您控制的某个常量中,并确保在重新加载文件时不要更改该常量。

答案 1 :(得分:0)

在输入这个问题时,坐在我旁边的同事想出来了。

Struct现在将类名作为其第一个参数。

所以在Ruby 1.9.3中,以下工作:

class << Struct.new('PerformableMethod', :object, :method, :args)