1

在 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

但是为什么结构不起作用?

4

2 回答 2

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的常量存放在您控制的某个地方,并确保在重新加载文件时不要更改该常量。

于 2013-06-12T08:11:23.910 回答
0

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

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

因此,在 Ruby 1.9.3 中,以下工作:

class << Struct.new('PerformableMethod', :object, :method, :args)
于 2012-05-25T17:49:59.567 回答