我已经纠结了好一阵子了。看看这个:
class SuperClass
def self.new(*args, **kwargs, &block)
i = allocate()
# Extra instance setup code here
i.send(:initialize, *args, **kwargs, &block)
return i
end
end
class Test < SuperClass
def initialize
puts "No args here"
end
end
类SuperClass
基本上"重新实现"默认的new
方法,以便在initialize
之前进行一些额外的初始化。
现在,下面的代码运行正常:
t = Test.allocate
t.send(:initialize, *[], **{}, &nil)
但是,这不是:
t = Test.new
ArgumentError:参数数目错误(1 for 0)From (pry):7:in ' initialize'
在SuperClass
这一行失败:
i.send(:initialize, *args, **kwargs, &block)
但显然它只有在new
方法中调用时才会失败。我已经确认args == []
, kwargs == {}
和block == nil
.
有人能解释一下吗?
Ruby版本:
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]
请不要建议我不要重载Class.new
。我知道我可以使用Class.inherited
和Class.append
获得相同的结果。这个问题只是关于为什么调用initialize
失败。
让我们看一个更简单的例子,特别是因为这个问题并不像问题和它的标题那样具体,但是你自己看看。
def m # takes no arguments
end
m(**{}) # no argument is passed
h = {}
m(**h) # an argument is passed => ArgumentError is raised
这个不一致是在2.2.1中引入的,目的是修复一个涉及**{}
的分段错误(Bug #10719)。将特殊情况下的**{}
提交为不传递参数。其他方式,如**Hash.new
和h={};**h
,仍然传递空哈希作为参数。
以前的版本始终会引发ArgumentError
(demo)。我可能是错的,但我相信这是有意的行为。然而,这可能是也可能不是那个人真正想要的。因此,如果您认为双散列空散列不应该传递参数(如目前的**{}
),因此工作方式类似于散列空数组,那么存在一个开放的问题(Bug #10856)。它还提到了这个相对较新的不一致
一个简单的*args
将捕获包括关键字参数在内的所有参数,以防您不需要在new
方法中单独引用kwargs
:
class SuperClass
def self.new(*args, &block)
i = allocate
# Extra instance setup code here
i.send(:initialize, *args, &block)
i
end
end