超级(&零)在红宝石中做什么?

snw*_*snw 7 ruby

我正在阅读concurrent-ruby的源代码,并遇到了这行ruby代码.

def initialize(*args, &block)
  super(&nil) # <--- ???
  synchronize { ns_initialize(*args, &block) }
end
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释它应该做什么吗?

max*_*ner 3

您必须首先了解&此处使用的运算符。参见示例:

# The & here converts a block argument to a proc
def a(&blk)
end

# The & here converts the proc to a block
a(&Proc.new { true })
Run Code Online (Sandbox Code Playgroud)

在 proc => block 的情况下,它还能够将一些对象变成 proc,例如:

# The symbol :class gets to_proc called here
[1].map(&:class)
Run Code Online (Sandbox Code Playgroud)

Symbol#to_proc产生相同的功能如下

[1].map(&Proc.new { |x| x.class })
Run Code Online (Sandbox Code Playgroud)

我不确定这方面的官方文档在哪里(欢迎指针),但从测试看来,&nil实际上根本没有将任何块传递给该方法 - 它没有任何效果:

def a
  block_given?
end

a {} # => true
a &:puts # => true
a &nil # => false
Run Code Online (Sandbox Code Playgroud)

现在已经解释清楚了,我可以继续说明为什么需要它。

如果省略括号super,所有参数都会被传递:

class A
  def initialize arg
    puts arg && block_given?
  end
end

class B < A
  def initialize arg
    super
  end
end

B.new(1) {}
# prints "true" - block and arg were both passed to super
Run Code Online (Sandbox Code Playgroud)

如果您不希望发生这种情况,可以手动将参数传递给super. 这有一个问题,我稍后会讨论:

class A
  def initialize arg1, arg2=nil
    puts arg1 && !arg2
  end
end

class B < A
  def initialize arg1, arg2=nil
    super arg1
  end
end

B.new 1, 2
# prints "true" - arg1 was passed to super but not arg2
Run Code Online (Sandbox Code Playgroud)

问题是,虽然您可以阻止传递位置参数和关键字参数,但这种方法不会阻止传递块:

class A
  def initialize arg1
    puts arg1 && block_given?
  end
end

class B < A
  def initialize arg1
    super arg1
  end
end

B.new(1) { }
# prints "true" - arg and block were both passed
Run Code Online (Sandbox Code Playgroud)

无论出于何种原因,重要的是不要发生这种情况,因此他们使用了一个我以前从未见过但似乎完成了工作的习语:&nil。它本质上是说“不将任何内容作为块传递”。我想如果你不这样做,那么块就会自动转发。

  • @snw `&amp;nil` 不传递空块,它不传递任何块。我不确定您是否可以说它“返回”任何内容,因为它在方法定义或调用之外不是有效的语法。我不确定你的意思是“在哪里处理这种特殊情况”。源代码中的位置在问题的评论中链接 (4认同)
  • 默认情况下,初始化有一个“超级”定义 - 尝试这个“class Foo;” def 初始化;极好的; 结尾; 结束`,它有效。至于他们为什么使用“super(&amp;:blk)”,我唯一能想到的是他们试图将其与“super”区分开来(如果不包含括号或参数,它会自动转发所有参数)。虽然我认为这与“super()”相同,所以不太确定重点是什么。 (2认同)