为什么" instance.send(:initialize,* args,** kwargs,& block)"仅在#new类中失败?

时间:2015-10-13 07:00:35

标签: ruby ruby-2.2

我已经坚持了很长一段时间了。看看这个:

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基本上&#34;重新实施&#34;默认的new方法,以便在initialize之前进行一些额外的初始化。

现在,以下工作正常:

t = Test.allocate
t.send(:initialize, *[], **{}, &nil)

然而,这不是:

t = Test.new
ArgumentError: wrong number of arguments (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.inheritedClass.append获得相同的结果。这个问题只是关于调用initialize失败的原因。

2 个答案:

答案 0 :(得分:4)

让我们来看一个更简单的例子,特别是因为这个问题并不像问题那样具体,而且它的标题看起来像是看起来像你自己一样。

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.newh={};**h这样的其他方式仍然会将空哈希作为参数传递。

以前的版本不断提升ArgumentErrordemo)。我可能错了,但我相信这是预期的行为。然而,它可能是也可能不是实际想要的。因此,如果你认为双splatting一个空哈希不应该传递一个参数(如此时的**{}),因此类似于splatting一个空数组,有一个公开的问题({{3 }})。它还提到了这种相对较新的不一致。

答案 1 :(得分:0)

如果您不需要在*args方法中单独引用kwargs,则简单的new将捕获包括关键字参数在内的所有参数:

class SuperClass
  def self.new(*args, &block)
    i = allocate

    # Extra instance setup code here

    i.send(:initialize, *args, &block)
    i
  end
end