在Ruby中,super(&nil)是什么意思?

7
我正在阅读concurrent-ruby的源代码,其中遇到了这行Ruby代码。

the source code for concurrent-ruby


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

有人能解释一下这个东西应该做什么吗?

2
可能是调用了父类的构造方法,没有传递代码块(&nil 可能是一个空代码块)。 - Guillaume
@Guillaume 但是超类没有定义初始化方法。 - seethrough
看起来这段代码来自这里,与线程的初始化有关。还可以参考@PeterO.在这里的回答。 - Cary Swoveland
@CarySwoveland 你不小心两次贴了同样的链接。 - max pleaner
@snw请查看我回答的编辑。 - max pleaner
1
谢谢,@max。我给出的第二个链接应该是这个。我相信这与你的答案相关。 - Cary Swoveland
1个回答

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 })

在 proc => 块的情况下,它也能将一些对象转换为procs,例如:
# The symbol :class gets to_proc called here
[1].map(&:class)

Symbol#to_proc 方法产生与以下代码相同的功能

[1].map(&Proc.new { |x| x.class })

我不确定官方文档的位置(欢迎提供指针),但从测试结果来看,&nil 实际上不会将任何块传递给该方法 - 它没有任何作用:

def a
  block_given?
end

a {} # => true
a &:puts # => true
a &nil # => false

现在已经解释清楚了,我可以继续说明为什么需要它。
如果您省略使用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

如果您不希望发生这种情况,可以手动传递参数给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

问题在于,虽然您可以防止传递位置参数和关键字参数,但这种方法无法阻止块被传递:
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

由于某种原因,这里很重要的是它不发生,所以他们使用了一个我之前从未见过但似乎能够完成工作的成语:&nil。它基本上是在说“将空内容传递为块”。我猜如果你不这样做,那么块会自动转发。


实际上并没有超级构造函数,至少我找不到它。 - seethrough
@seethrough 好的,我也看到了你留下的另一条评论,但是它是用不同的用户名发布的,所以我没有意识到你是 OP。#initialize 在所有类中都会自动定义,因此无论如何都会有一个 super - max pleaner
@max_pleaner 什么是OP? - seethrough
2
默认情况下,初始化有一个“super”定义 - 尝试使用class Foo; def initialize; super; end; end,它可以正常工作。至于为什么要使用super(&:blk),我唯一能想到的是他们试图将其与super区分开来(如果您不包括括号或参数,则自动转发所有参数)。虽然我认为这与super()相同,所以不太确定有什么意义。 - max pleaner
4
@snw &nil 并不是传递一个空块,它根本不传递任何块。我甚至不确定你是否可以说它"返回"任何东西,因为除了方法定义或调用之外,在语法上它都是无效的。我不确定你所说的"处理这个异常情况的地方"是什么意思。源代码中处理此异常情况的位置已在问题的注释中链接了。 - max pleaner
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接