2012-05-25 32 views
1

在Ruby 1.8.6,我可以写class PerformableMethod < Struct.new(:object, :method, :args)从结构继承与使用attr_accessible

现在的Ruby 1.9.3,抛出一个错误:superclass mismatch for class PerformableMethod

如果我更改代码以它的工作原理:

class PerformableMethod 
    attr_accessor :object, :method_name, :args 

但为什么不结构工作?

回答

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 

...因为每当你的类定义运行时,它正在申报新StructMyClass超品牌。提供类名到Struct.new()没有帮助,如第二个代码块所示;这只是增加了一个关于重新定义常量的警告,然后打开该类失败。

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

0

在输入这个问题时,我旁边坐的同事发现了这个问题。

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

所以红宝石1.9.3以下工作:

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

这将打开'Struct'的单例类。这与问题中的说法不一样。 – clacke